Search code examples
powershellserverinteractiveadministration

Run interactive 'master' PowerShell script on local PC as well as remote PCs and log


I have a massive (983 line) interactive PowerShell script that I wrote to manage pretty much all aspects of a local server. I have a text file with a list of servers. I want to get crazy with it.

Text File Contents:

Server1Name
Server2Name

PowerShell Interactive Menu:

Write-Host "Welcome to the environment control script."
Write-Host " "
Write-Host "What would you like to do? Select the number:"
Write-Host "========================================================================="
Write-Host "1. Create a backup of the environment (existing servers)"
Write-Host "2. Backup environment and deploy updated environment (existing servers)"
Write-Host "3. Deploy new environment including IIS (clean servers)"
Write-Host "4. Deploy just IIS (clean servers)"
Write-Host "5. Remove Build w/ backup and cleanup IIS (existing servers)"
Write-Host "6. Remove Build w/out backup and cleanup IIS (existing servers)"
Write-Host "7. Remove and cleanup only IIS (existing servers)"
Write-Host "8. Deploy new DLL's (existing servers)"
Write-Host "9. [EXIT]" -foregroundcolor "yellow"
Write-Host " "

Purpose:

Trying to get away from having 1000 batch files on my servers

Example:

I run script on "Master" server and there are 10 other servers in the text file. At first, the script is ONLY running on the master server. Once I pick option 6, a command is run to do the same commands across all of the 11 servers (master + 10 others).

I know how to run the same script across servers if it was say a simple file copy or service reset (no interaction from the user) using stuff like invoke-command or enter-pssession,etc...however, in my case I'll have to remote to each server because it's interactive...unless there is a way to do this?

Also, if possible, enable logging so I can confirm that each PC ran the script and did everything successfully. Right now, I have it starting a transcript and stopping at the end. Works great locally.

Any help would be appreciated.

Update: 3/8/16

So, @Cobster has helped me out and we are 99% there.

Using the follow code, it looks like the script is attempting to run, however there is one more issue.

$sessions = New-PSSession -ComputerName $servers 
$job = Invoke-Command -Session $sessions -ScriptBlock ${function:Backup} -AsJob

If you want a different job for each machine, you can do the following:

$jobs = $sessions | ForEach-Object { Invoke-Command -Session $_ -ScriptBlock ${function:Backup} -AsJob } 
Wait-Job -Job $jobs

The issue is that when this is done, the invoke-command doesn't seem to import all of my previously declared variables at the top of my script (which includes virtually ALL of my paths, etc. because they are not defined within that function.

This results in a bunch of these types of errors (7 to be exact, one for each of my test-path checks before performing a step):

Cannot bind argument to parameter 'Path' because it is null.
    + CategoryInfo          : InvalidData: (:) [Test-Path], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.TestPathCommand
    + PSComputerName        : *ServerName*

Solution:

Use -ArgumentList $variable1, $variable2 in the invoke-command and

param ( $variable1, $variable2 ) method within the function...courtesy of Cobster.


Solution

  • Invoke-Command can be run in the background by using the -AsJob switch.

    Logging is also possible by using the Receive-Job cmdlet to get the output of each of the background jobs upon completion.