Scripte und Dateien per Powershell über mehrere Server verteilen / ausrollen

Wir kennen doch alle die nervige Situation, in der wir plötzlich sämtliche unserer erstellten Powershell oder Batchscripte in der Serverlandschaft aktualisieren müssen. Die Menge der Server entscheidet ob es eine Qual für uns wird oder nur eine kurze Nummer bleibt.
Sind die Scripte aktualisiert, fällt oft beim Ausführen der Powershell-Scripte auf den Servern aus, dass mindestens ein Server einen Sonderfall darstellt und das Script zum Fehler führt.
Also beginnt der ganze Spaß wieder von vorne…

mit Powershell Dateien und Scipte verteilen

Ich erledige sehr viele wiederkehrende Aufgaben und Prozesse per Powershell und muss des Öfteren meine bestehende Scripte erweitern oder austauschen. Die Serverlandschaft umfasst etwa 1200-1500 Windows Server (okay, meine Scripte laufen zum Glück nicht auf jeden Server 😉 ) was das ganz schnell zur Qual werden kann.

Um mich von diesen Qualen zu erlösen, habe ich mir ein weiteres Powershell-Script geschrieben welches Scripte ausrollt und im Anschluss per scheduled Tasks ausführt. Seitdem läuft das Deployment der Scripte locker und flockig, ganz nebenbei.

Wie das Powershell-Script funktioniert

Mein Deployment-Script erfüllt zwei Aufgaben, kopieren und anschließend das Starten der neuen Version. Manchmal reicht es auch aus nur Scripte zu aktualisieren, weshalb man das über die beiden folgenden Variablen steuern kann.

$copy_files=1 # 1=enable copy 0=disable copy
$start_scheduled_tasks=1 # 1=start script 0=disable

Quelle, Ziel und scheduled Tasks wird via verschachteltem Array festgelegt: $script_sources, $script_tasks, $script_targets

$script_sources=@{"scriptname1.ps1"="C:\Scripts\DeployScripts\scripts_for_deployment\";
                    scriptname2.ps1"="C:\Scripts\DeployScripts\scripts_for_deployment\";
                    }

$script_tasks=@{"scriptname1.ps1"="Serverinventory";
                    "scriptname2.ps1"="AD-Export";
                    }

$script_targets=@{"scriptname1.ps1"=@{
                            "server1_fqdn"="\c$\scripts";
                            "server2_fqdn"="\c$\scripts";
                    };
                    "scriptname2.ps1"=@{
                            "server3_fqdn"="\c$\scripts";
                            "server4_fqdn"="\c$\scripts";
                    }
                 }

Folgender Powershell Code erzeugt folgende Ergebnisse:

  • Quelle ($script_sources): Serverinventory.ps1 => C:\Scripts\DeployScripts\scripts_for_deployment\
  • Ziel ($script_targets): Serverinventory.ps1 => \dc12.pri.de\c$\scripts
  • scheduled Task ($script_tasks): für das Script „Serverinventory.ps1“ lautet „Serverinventory“
$script_sources=@{"Serverinventory.ps1"="C:\Scripts\DeployScripts\scripts_for_deployment\";
                    #"AD-export.ps1"="C:\Scripts\DeployScripts\scripts_for_deployment\";
                    }

$script_tasks=@{"Serverinventory.ps1"="Serverinventory";
                    "AD-export.ps1"="AD-Export";
                    }

$script_targets=@{"Serverinventory.ps1"=@{
                            <#"wcdc12.site1.local"="\c$\scripts";
                            "wdc11.site2.local.de"="\c$\scripts";#>
                            "dc12.pri.de"="\c$\scripts";
                            "dc12.ida.de"="\c$\scripts";
                    };
                    <#"AD-export.ps1"=@{
                            "wfile01.site1.local"="\c$\scripts";
                            "wfile01.site2.local"="\c$\scripts";
                    }#>
                 }

Die Angaben für das Zweite Script sind auskommentiert.

das komplette Powershell-Script

# Requirements:
# - powershell 2.0
# - need to run under domain admin user
#
# Configuration:
# - configure only
# -> $script_sources
# -> $script_tasks
# -> $script_targets
# -> $copy_files
# -> $start_scheduled_tasks
#
#### Configuration ####
$script_version="20190315"

$copy_files=1
$start_scheduled_tasks=1

$script_sources=@{"Serverinventory.ps1"="C:\Scripts\DeployScripts\scripts_for_deployment\";
                    #"AD-export.ps1"="C:\Scripts\DeployScripts\scripts_for_deployment\";
                    }

$script_tasks=@{"Serverinventory.ps1"="Serverinventory";
                    "AD-export.ps1"="AD-Export";
                    }

$script_targets=@{"Serverinventory.ps1"=@{
                            <#"wcdc12.site1.local"="\c$\scripts";
                            "wdc11.site2.local.de"="\c$\scripts";#>
                            "dc12.pri.de"="\c$\scripts";
                            "dc12.ida.de"="\c$\scripts";
                    };
                    <#"AD-export.ps1"=@{
                            "wfile01.site1.local"="\c$\scripts";
                            "wfile01.site2.local"="\c$\scripts";
                    }#>
                 }

$scriptname="FLEET_update-scripts_start-tasks.ps1"

foreach ($scriptfile in $script_targets.Keys){
    
        $script_name=$scriptfile

        write-host "-"$scriptfile

       foreach ($key in $script_targets.$scriptfile.Keys){
        
        if($copy_files -eq 1){
            $script_target_server=$key
            $script_target_folder=$script_targets.$scriptfile.$key

            $source=$script_sources.$scriptfile+$scriptfile
            $destination="\\"+$script_target_server+$script_target_folder

            write-host "-> copy $source to $destination"
        }
                   
        if(Test-Connection $script_target_server -Count 1){
        
            if($copy_files -eq 1){

                $tmp=$destination+"\"+$scriptfile
                $dir=Get-ChildItem -Path $tmp 
                write-host "--> old LastWriteTime: "$dir.LastWriteTime" / old filesize:"$dir.Length

                Copy-Item -Path $source -Destination $destination -Force
                $dir=Get-ChildItem -Path $tmp 
                write-host "--> new LastWriteTime: "$dir.LastWriteTime" / new filesize:"$dir.Length
            }

            if($start_scheduled_tasks -eq 1){

                write-host "-- start scheduled task: "$script_tasks.$scriptfile.ToString()
                SCHTASKS /run /s $script_target_server /TN $script_tasks.$scriptfile.ToString()

                write-host "-----------------------"
            }
        }else{
            write-host "- ERROR: $script_target_server not available"
        }
       }
}