This is a complicated issue and may only make sense to me, but I’d like to document for future reference. I’ll try to simplify as much as possible to stick to the crux of the matter: remotely executing powershell scripts from powershell scripts.
Pretend I have 3 web servers. On each server a powershell maintenance script perpetually runs (infinite loop). If I have a new web site to build, I edit a text file on a network folder. The maintenance scripts see this and execute a “createsite” script. Sometimes, due to down time if IIS needs to be stopped, I need these scripts to run in an orderly fashion. So one maintenance script is always a “master” of the others.
I’ve finally gotten sick of having a perpetual script running on each server (using resources and requiring an interactive login). What I want is one server which coordinates the execution of all my other little task scripts on the 3 web servers. Yup, I need to figure out remote execution!
Yes, Powershell v2 has decent remoting capabilities, but I can’t effectively leverage them quickly. We still use IIS6, my web servers have Powershell v1, and there is a lot of rewrite time for the scripts to update them properly. Instead, I’d like to quickly get going with this architecture with as little effort as possible.
I’ll use psexec and Powershell.
First, I need to make sure the account that Powershell will run under has a profile file set up. All of my scripts run out of d:\setup\scripts. If I want to start a remote powershell under a user and be able to relatively reference other scripts inside my first one, I need that user’s profile to start in d:\setup\scripts.
Create the file profile.ps1 in ..\documents and settings\script user\my documents\WindowsPowerShell\. The contents:
set-location d:\setup\scripts
This is the call I do on another server with an account that I designate as my web installer:
./psexec \\WEBSERVER1 -u DOMAIN\USER -p ‘PASSWORD’ /accepteula cmd /c “echo . | powershell -noninteractive -command `”& ‘d:\setup\scripts\createsites.ps1’`””
Whoa, wait, what’s the “echo . |” thing in there? That allows me to see the progress of my script, and properly lets psexec work on the target machine so my calling script can continue on with life. I found that just calling a powershell instance led to powershell/psexec never executing properly.
Did I need that -u and -p declared? Strangely, I did, even though the script was running as that user. If this wasn’t declared, I don’t think the Powershell profile was loading properly.
Questions?
Why don’t I use functions in my maintenance script instead of a separate script for my major tasks? I have many other pieces beyond a “createsites” task, some of which I call separately anyway. I’d much rather manage smaller scripts than one large beast of one. I’m not a software developer. 🙂
Why not use Task Scheduler? Let’s just say I don’t want Task Scheduler running on production web servers. And I want all my web servers to be managed the same.
I’m just updating this entry with a new line that includes a few psexec switches:
$invokeline = “./psexec \\WEBSERVER -i -d -u DOMAIN\USER -p ‘PASSWORD’ /accepteula cmd /c `”echo . | powershell -noninteractive -command `”`”&`” ‘d:\path\script.ps1’`”`””
and this from 9/2011: ./psexec \\WEBSERVER -i -d -u DOMAIN\user -p ‘xxxxxxx’ /accepteula cmd /c “echo . | powershell -noninteractive -command `” & ‘d:\setup\scripts\myscript.ps1’`” ”