I am trying to run a PowerShell script Daily.ps1 on start-up, however, due to administrator settings (I cannot run as admin, that is not an option), I cannot run it through the Task Scheduler. For example, this is the contents of Daily.ps1:
if (1 -eq 1) {
"Hello there!"
}
So I tried to have a batch script Daily.cmd run on start up (through the start-up folder), which runs, but I cannot get it run the Daily.ps1, and I get a message saying running scripts is disabled. (Both files are in the same directory)
powershell C:\Users\Simon\Desktop\Daily.ps1
File C:\Users\Simon\Desktop\Daily.ps1 cannot be loaded because running scripts is disabled on this system
I then tried using this line of code from a trick I learned to bypass running scripts directly:
powershell cat Daily.ps1 | powershell invoke-expression
This works but only for one liners. So I added the -raw flag for
cat, which works when in powershell, but not in CMD. For some reason, Daily.ps1's text is still stored as an array of strings. (apologies for formatting)
cmdlet Invoke-Expression at command pipeline position 1
Supply values for the following parameters:
Command: if (1 -eq 1) {
invoke-expression : At line:1 char:14
if (1 -eq 1) {
Missing closing '}' in statement block or type definition.
At line:1 char:1
invoke-expression ~~~~~~~~~~~~~~~~~
So I tried to add this to Daily.cmd:
powershell
cat -raw Daily.ps1 | powershell-invoke-expression
However, the rest of the script doesn't get executed at all once I enter PowerShell.
I don't know to get Daily.ps1 to run through a batch command. Is there a way I missed, or is one of the ways I tried faulty (without admin rights)?
Edit: To clarify, ExecutionPolicy is set to Restricted, and that cannot be changed. Additionally, I can run PowerShell scripts fine through right clicking the file and running with PS.
Create a scheduled task to run at computer startup. Put powershell.exe in the field "program/script" and -File "C:\path\to\your.ps1" in the field "arguments" (you may want to avoid placing the script in a user profile). Set the task to run whether the user is logged on or not.
I found an answer!
After trying many different methods, I came across this line of code that allows you to run PS scripts if ExecutionProperty is set to restricted:
start powershell "cat -raw C:\Users\Simon\Desktop\Daily.ps1 | invoke-expression"
This runs powershell and uses the trick of piping the results of cat -raw [file.ps1] to invoke-expression. This is useful workaround if ExecutionProperty is set to restricted.
Then you can save this line to a .cmd or .bat file and use either Task Scheduler (more customizability) or put it in the startup folder.
P.S. for everyone who kept saying change the ExecutionProperty to something other than restricted. I clearly stated multiple times that I cannot do that(not admin), nor will the Sys Admin do that, nor will it ever happen(must stay restricted) :)
Related
When you're in file explorer you can click on File > Open Windows Powershell(or its icon in the Quick Access Toolbar) to start an instance of Powershell in the directory that your file explorer is in. I would like to then automatically run a simple command in this directory and close the Powershell window after it is done.
I have tried adding my command to my Powershell Profile but it executes before the path variable has been set and it runs with $pwd being equal to C:\Users\MyUsername (my home directory) or C:\WINDOWS\system32 (seems to be a race condition of some sort, no idea why it does one or the other). To the best of my understanding this is because the file explorer "open in powershell button" opens powershell and THEN cd's to the directory I was in in file explorer. So when the profile.ps1 is ran it is using the only directories it knows if since the cd call hasn't been made yet. This is similar to running the command start powershell.exe in cmd vs start powershell.exe -command "cd 'C:\wherever'". The former correctly runs my profile command while the latter uses the current directory of cmd and not the C:\wherever.
So, obviously the $pwd variable is being assigned at different times in the case of opening it from cmd and opening it from file explorer. Is there some way to delay the execution of a command in the profile until after the shell has fully loaded? Simply sleeping the script doesn't help.
Alternatively, if anyone knows how to edit the registry so that I can change the behavior of clicking File > Open Windows Powershell (since it must have access to some variable storing the current directory and I assume it calls the Powershell executable with this variable as an argument being cd'd to), that would work too.
Then again I could be incredibly naive about how File > Open Windows Powershell and the Powershell instantiation process works.
Any help is greatly appreciated, thank you!
I figured it out in the most hacky, gross way ever, but without easy access to Windows internals this is the only working method I could find. I set up my powershell profile to make my window title my prompt like so:
function Prompt
{
$host.ui.RawUI.WindowTitle = $(get-location)
“PS> “
}
Then I set up a task in the Task Scheduler that was triggered by powershell reaching its prompt (there are 3 possible hooks, when the console is starting up, when it starts an IPC listening thread, and when the console is ready for input). I used the Event Viewer to do this (I was going to post screenshots but I don't have 10 reputation yet).
Then, I set the action on this task to run the script shown below, which reads from the window title of my first instance of powershell
Start-Sleep -s 1
$A = Get-Process -Name powershell | Where-Object -FilterScript {$_.Id -ne $PID}
$B = $A.MainWindowTitle
& C:\Program` Files\MyProgram\MyProgram.exe "$B"
stop-process -Id $A.Id
stop-process -Id $PID
This whole menagerie of events properly runs my program with the current file explorer directory as an argument (and then closes powershell) when I click the little powershell icon on the quick access toolbar in file explorer.
Found a much cleaner and faster way to do this. All I had to do was set up my profile to look like this, no tasks or second instance of powershell required
function Prompt
{
& C:\Program` Files\MyProgram\MyProgram.exe "$pwd"
stop-process -Id $PID
}
So here's the deal. Because of a number of... let's just say not PowerShell smart people who will be using an incredibly complex application that I just finished, I need the ability to package it in an exe wrapper.
This shouldn't be that hard
I was able to successfully use PS2EXE, except for some reason with AD, it throws out a whooooole bunch of AD text that I can't get rid of. Tried to fix that for a few days before getting frustrated and moving on.
Then, I discovered PowerGUI. I can't say that I like it, at all. However, its compiler was exactly what I was looking for! Except for the fact that Exchange 2010 snap-ins are not compatible with .NET 4.5 through this application.
I want to make it very clear that my script works perfectly on multiple different computers, but as soon as I use any of these tools, everything breaks.
An exe is the best thing that I can think of to simplify the interface, and keep the Technically Intellectually Stunted from breaking everything, or running to me with every little error because they somehow got into the code and typed something and saved it, and now nothing works and it's the end of the world and they have no idea what happened.
If you guys know of any tools to wrap this up into an exe, or have any other ideas on how to help, I would really appreciate anything you guys can give me.
You have never failed me in the past!
From my point of view if you really want an EXE file you should write a .NET application, it's not so hard to embed PowerShell CmdLets.
In order to avoid end user modifying your code I know two solutions :
First : set execution policy to AllSigned on the user computer and sign the scripts you deploy. You can manage to use our own certificates (not expensive at all) or public certificates (more expensive). One of the drawback of this solution is that it does not prevent users from seeing the code. Another big drawback is that a PKI and sign code infrastructure is a lot of wast time.
Second : for non interactive scripts (be carefull it's a kind of makeshift job) :
Create a new user account
Only allow access to the script file for the new account.
Set up a task in the Windows scheduler to run that script file with PowerShell under that specific account. The permissions for the scheduled tasks allow read and execute access to the user(s). Then set the task to "disabled".
Whenever the script file needs to be run, the corresponding task is manually started by the user.
Using this solution will also allow you to remote execute your script.
When I had a similar deployment problem - 1) user's didn't know powershell 2) I didn't want them to have to understand things like execution policy, 3) how to start PS, 4) etc. I wrapped it in a batch file. I also wanted to make sure that experienced PS users still had the capabilities of PS, so the batch file determined if it was running under PS or not and ran in the current PS session if applicable. I was never too worried that users would mess with the script - they were happy if it "just worked". So whether users liked Explorer, CMD.EXE, or PS, they all were accommodated.
The batch file I wrote first runs a bit of powershell code to determine if the process of the batch file is the grandchild of a powershell process. If it is then the batch file is being invoked from PS. The execution policy is also checked and if it is lenient enough then Wscript.SendKeys is used to send keystrokes to PS to get the script running in the current PS session. If it isn't then it starts a new PS session using -ExecutionPolicy parameter and passes the script as a command line argument (-Command).
This bit of powershell code communicates back to the .CMD file using a return code. Sorry it's cryptic, but the length of command line parameters is limited. Here's the code:
set scr= $mp=[diagnostics.process]::getcurrentprocess().id
set scr=%scr%; $pp=([wmi]\"win32_process.handle='$mp'\").parentprocessid
set scr=%scr%; $gp=([wmi]\"win32_process.handle='$pp'\").parentprocessid
set scr=%scr%; $ep=[int][microsoft.powershell.executionpolicy](get-executionpolicy)
set scr=%scr%; try {$pnp=1-[int](([wmi]\"win32_process.handle='$gp'\").Name -eq \"powershell.exe\")
set scr=%scr%; } catch {$pnp=1}
set scr=%scr%; $ev = (8 * $pnp + $ep) -band 0xB; %wo% pp: $pp gp: $gp ev: $ev; if ($ev -le 1) {
set scr=%scr% %wo% Launching within existing powershell session...`n;
set scr=%scr% $w=new-object -com wscript.shell;$null=$w.appactivate($gp);
set scr=%scr%; $w.sendkeys(\"^&{{}`$st =cat "%me%";`$sc=`$st -join [char]10 -split 'rem PS script';
set scr=%scr% `$script:myArgs = `\" %*`\";`$sb=[scriptblock]::create{(} `$sc[3]{)};. `$sb{}}~\")
set scr=%scr%; }
set scr=%scr%; exit $ev
powershell -noprofile -Command %scr%
%wo% is to allow debugging this "checker script". If debugging is on the %wo% is set to write-host. Otherwise it is set to define a "null" function and then invoke the null function. The null doesn't do anything so the message that is the argument to the function is not output.
Note the escaping when invoking SendKeys. ^ is the CMD.EXE escape character and SendKeys has it's own escape mechanism, as does PS.
If run from PS you end up in a PS session thanks to SendKeys. Otherwise the batch file does this:
set scr= ren function:prompt prompto
set scr=%scr%; function prompt{ 'myApp: '+(prompto)}
set scr=%scr%; $st= (cat %me%) -join \"`n\";
set scr=%scr%; $sx=($st -split 'rem PS script')
set scr=%scr%; $sc=$sx[3]
set scr=%scr%; %wo% myArgs: $myArgs script length: $sc.length
set scr=%scr%; ^&{$script:myArgs=\"%*\"; iex $sc}
title MyApp
rem Change the number of lines on the console if currently set to 25
for /f "tokens=2" %%i in ('mode con^|findstr Lines:') do if %%i LEQ 25 (mode con lines=50&color 5F)
powershell -noexit -noprofile -command "%scr%"
This "helper script" also can't be too long. So the helper script reads the original .CMD file and then splits it by using the string 'rem PS script'. That string will be in both this helper script as well as in the batch file (separating the batch file statements from PS statements). In my case the string is also in the batch file comments, so that is why the index of 3 is used.
Your PS script can define functions or a module. Your PS script can also output some introductory info to explain to users how to get started, how to get help, or whatever you want.
Rather than just using the PS command line, your PS script could create it's own interactive environment (using Read-Host for example). However I didn't want to do that because it would have prevented experienced PS users from using their knowledge about PS. For example if your script requires a username/password, an experienced PS user could use get-credential to create a credential to send to your script.
I downloaded PS script from http://poshcode.org/2216. Whenever I try to run this script, security popup appears: "Run only scripts that you trust. While Scripts from the internet can be usefull, this script can potentially harm your computer. If you trust this script, use the Unblock-File cmdlet to allow the script to run without this warning message. (...)".
So I executed Unblock-File .\Send-File.ps1 but nothing changed. I also tried other variations like Get-Content .\SendFile | Unblock-File. Nothing seems to work.
Does anyone know what is the proper way to unblock PowerShell script? Thanks in advance.
You can also wipe the ZoneId from the alternate data stream :
set-Content Send-File.ps1 -Stream zone.identifier -Value ''
To unblock a particular script file, Sam's answer will be ok.
You also can run a script without actually unblocking it by bypassing your PowerShell execution policy explicitly.
To do that execute the following console command:
powershell.exe -ExecutionPolicy Bypass .\Send-File.ps1
... and the script will start
Right-click the downloaded script, select properties and unblock.
By default the downloaded PS script will be treated as unsafe. You need to set Powershell's execution policy to bypass the security check for this particular file.
To do that, execute:
Set-ExecutionPolicy Bypass -File (...)
(Note that it is possible to run the above command with no File specified, which globally sets the execution policy to bypass the security check; we do not recommend you do that!)
Here's my configuration:
On the build log, I only see the output of the first two lines, and then "Process exited with code 0" as the last output of this build step.
I tried opening a terminal in the build server in the SYSTEM account (using PsTools), since Team City is configured to run under said account. Then, I created a Test.ps1 file with the same content and ran a command just like Team City's:
[Step 1/4] Starting: C:\Windows\system32\cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NonInteractive -Command - <C:\TeamCity\buildAgent\temp\buildTmp\powershell5129275380148486045.ps1 && exit /b %ERRORLEVEL%
(except for the path to the .ps1 file and the cmd.exe initial part, of course). I saw the output of the two first lines, and then the terminal disappeared all of a sudden!
Where did I mess up? I'm new to Powershell, by the way.
The stdin command option of Powershell has some weirdness around multiline commands like that.
You script in the following form would work:
write-host "test"
write-host "test2"
if("1" -eq "1"){write-host "test3 in if"} else {write-host "test4 in else"}
The ideal way would be to use the Script : File option in TeamCity which will will run the script you specify using the -File parameter to Powershell.
If you don't want to have a file and having VCS, in the current setup, change Script Execution Mode to Execute .ps1 file with -File argument.
I've had this problem with inline powershell scripts with TeamCity (right up until the current version of 7.1.3). I've found the problem to be the tab character rather than multi-line statements. Try replacing the tab characters with spaces (while still remaining multi-line) and the script should run fine.
You could try putting the brace opening the block on the same line as the If.
I.e.,
If ('1' -eq '1') {
...
}
Else {
...
}
That's the usual styling you see with Powershell, and obviously, putting the braces on the next line can cause problems.
I'm using Hudson version 1.324 for CI and have a couple of issues:
Environment:
Windows Server 2008
Powershell v1.0
Hudson 1.324 running as a service
Hudson Powershell Plugin installed
Psake (aka. "Powershell Make/Rake" available from Github) 0.23
(All current/latest versions as of this initial post)
I have a Powershell (PS) script that works to compile, run NUnit tests, and if successful, create a 7z file of the output. The PS script works from the command line, on both my local development box as well as the CI server where Hudson is installed.
1) Execution Policy with Powershell.
I initially ran a PS console on the server, ran Set-ExecutionPolicy Unrestricted, which allows any script to be run. (Yes, I realize the security concerns here, I'm trying to get something to work and Unrestricted should remove the security issues so I can focus on other problems.)
[This worked, and allowed me to fire off the PS build script from Hudson yesterday. I then encountered another problem, but we'll discuss that more in item #2.]
Once Hudson could fire off a PS script, it complained with the following error:
"C:\Windows\system32\WindowsPowerShell\v1.0\powershell "&
'OzSystems.Tools\psake\psake.ps1' '.\oz-build.ps1'" The term
'OzSystems.Tools\psake\psake.ps1' is not recognized as a cmdlet, funct
ion, operable program, or script file. Verify the term and try again.
At line:1 char:2
+ & <<<< 'OzSystems.Tools\psake\psake.ps1' '.\oz-build.ps1'"
Using the same command line, I am able to successfully execute the PS script from the command line manually. However Hudson is unable to get PS to do the same. After looking at additional PS documentation I also tried this:
"& 'OzSystems.Tools\psake\psake.ps1' '.\oz-build.ps1'"
and got a similar error. There does not appear to be any documentation for the Powershell plugin for Hudson. I've gone through all the Powershell plugin files and don't see anything that's configurable. I can't find a log file for Hudson to get additional information.
Can anyone help me past this?
2) I spent yesterday wrestling with #1. I came in this AM and tried to dig in again, after restarting the Hudson server/service, and now it appears that the ExecutionPolicy has been reset to Restricted. I did what worked yesterday, opened a PS console and Set-ExecutionPolicy to Unrestricted. It shows Unrestricted in the PS console, but Hudson says that it doesn't have rights to execution PS scripts. I reopened a new PS console and confirmed that the ExecutionPolicy is still Unrestriced -- it is. But Hudson evidently is not aware of this change. Restarting Hudson service again does not change Hudson's view of the policy.
Does anyone know what's going on here?
Thanks, Derek
I just ran into the problem of running powershell scripts in hudson. The thing is that you are running a 32-bit process of Java, and you've configured Hudson for 64-bit but not for 32-bit. See the following thread we created at microsoft.
http://social.technet.microsoft.com/Forums/en/winserverpowershell/thread/a9c08f7e-c557-46eb-b8a6-a19ba457e26d
If your lazy.
1. Start powershell (x86) from the start menu as administrator
2. Set the execution policy to remotesigned
Run this once and your homefree.
When Running PowerShell from a scheduled task or Hudson you want to:
Specify the -ExecutionPolicy parameter (in your case: -Ex Unrestricted)
Specify that command using either -Command { ... } or -File NOT BOTH and not without specifying which you mean.
Try this (except that I don't recommend using relative paths):
PowerShell.exe -Ex Unrestricted -Command "C:\Path\To\OzSystems.Tools\psake\psake.ps1" ".\oz-build.ps1"
To be clear, this will work too:
PowerShell.exe -Ex Unrestricted -Command "&{&'OzSystems.Tools\psake\psake.ps1' '.\oz-build.ps1'}"
The first string after -Command is interpreted as THE NAME OF A COMMAND, and every parameter after that is just passed to that command as a parameter. The string is NOT a script, it's the name of a command (in this case, a script file)... you cannot put "&'OzSystems.Tools\psake\psake.ps1'" but you can put "OzSystems.Tools\psake\psake.ps1" even if it has spaces.
To quote from the help (run PowerShell -?) emphasis mine:
-Command
Executes the specified commands (and any parameters) as though they were
typed at the Windows PowerShell command prompt, and then exits, unless
NoExit is specified. The value of Command can be "-", a string. or a
script block.
If the value of Command is "-", the command text is read from standard
input.
If the value of Command is a script block, the script block must be enclosed
in braces ({}). You can specify a script block only when running PowerShell.exe
in Windows PowerShell. The results of the script block are returned
to the parent shell as deserialized XML objects, not live objects.
If the value of Command is a string, Command must be the last parameter
in the command , because any characters typed after the command are
interpreted as the command arguments.
I have been having the same problems as you (as you've seen from my comments). I have given up on the powershell launcher and moved to running things using the batch file launcher. Even though I had set the system to unrestricted that setting didn't seem to matter to hudson's launcher. I don't know if it runs in some other context or something, even adding things to the global profile.ps1 didn't seem to help. What I ended up doing was running
powershell " set-executionpolicy Unrestricted; & 'somefile.ps1'"
which does what I need, although it isn't ideal. I've e-mailed the plugin author about this and will update.
For question #1, try this (assuming you are using PowerShell 2.0):
"C:\Windows\system32\WindowsPowerShell\v1.0\powershell -executionPolicy Unrestricted -file OzSystems.Tools\psake\psake.ps1 C:\{path}\oz-build.ps1"
You are using "." for the path to oz-build.ps1. I suspect you will need to provide the full path to your oz-build.ps1 file to make this work. Unless the infrastructure that executes the command above happens to have the current dir set correctly. And even if it is set correctly for the "process", that only matters to .NET/Win32 API calls and not to PowerShell cmdlets. Current dir in PowerShell is tracked differently than the process's current dir because PowerShell can have multiple runspaces running simultaneously. That sort of global, mutable value doesn't work in this concurrent scenario.
As for question #2, what account does the Hudson service run under? Make sure that account has executed Set-ExecutionPolicy RemoteSigned (or unrestricted).
I just got through this exact problem. What a pain!
If you are running a 32-bit JVM on a 64-bit Windows, make sure that you set the execution policy for the 32-bit Powershell interface. I found my 32 bit executable here:
C:\Windows\syswow64\Windowspowershell\v1.0\powerhsell.exe
The 32- and 64-bit Powershell environments are completely distinct so setting the execution policy in one has no effect on the other.