Automating installations on multiple servers

I once did a quite big installation on around 80 servers of which could not be installed by wds or by using a image. I had to automate the process using powershell, check it out and hopefully you will get inspiration on how youd do it.

 


<#
 .SYNOPSIS
 This script is a package of functions used by the Install_RBIK.ps1 script
 .DESCRIPTION
 This script is a package of function used by the Install_RBIK.ps1 script
 RBIK stands for "Razorblade Installation Kit"

 .EXAMPLE
 In another script call upon this script with the followinf commands
 $PSScriptRoot = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition
 . $PSScriptRoot\powershell_repository\installation_functions.ps1;
 This will load the script functions into memory.
 #>
 $Version = "2.0"
 Write-Host "Installation_Function version: $Version is loaded";


Function Log-Write
{
    <#
    .SYNOPSIS
    This function will let you log to a file.
    .DESCRIPTION
    This function will let you create and add
    log entries to a log file.
    .EXAMPLE
    .\Log-Write -Value 'My custom log Entry' -Name 'My Custom Log Name' -Path 'H:\My_Custom_Log_Path\'
    In this example H:\My_Custom_Log_Path\ would get a new Log file named 'My Custom Log Name' with the content of Value timestamped.
    #>
    Param (
        [string]$Value="test",
        [string]$Name=$cfg['log_name'], 
        [string]$LogPath=$cfg['log_path'],
        [switch]$NoDate=$False
    )
    
    $Logfile = "$LogPath$(get-date -Format ('yyyy-MM-dd')) - $Name";

    
    if ($NoDate -eq $False)
    {
        $Value = $(get-date -Format ('yyyy-MM-dd HH:mm:ss')) + " - $Value";
    }
  
    if (!(Test-Path $Logfile))
    {
       Try{
           $NULL = New-Item $Logfile -type file -Force -ErrorAction Stop;
       }
       Catch{
           Write-Host "Could not create logfile: $Logfile because of: $_";
           Exit;
       }
    }
    Try{
        Add-content $Logfile -value $Value -ErrorAction Stop;
        Write-Output $Value;
    }
    Catch{
        Write-Host "Could not add content to logfile $Logfile, because of $_";
        Exit;
    }
}



Function Get-InstallationProcess
{
    <#
    .SYNOPSIS
    This will check the installation process
    .DESCRIPTION
    The installation process is stored in a file,
    this will retreive the current status of the installation
    and return the value
   .EXAMPLE
    .\Get-InstallationProcess -File "C:\InstallationProcess.txt"
    #>
   Param (
        [string]$File = $cfg['installationprocessfile']
   )
    if(!(Test-Path $File))
    {
        Try{
            New-Item -Path $File -ItemType File -Force -ErrorAction Stop;

            Log-Write "initializing the installation process in $File";

            Set-Content $File -Value "0";

            Return "0";
        }
        Catch {
            Log-Write "Could not create the initial installation process file because of: $_";

            Exit;
        }
    }
    else
    {
        Return Get-Content $File;
    }
}


Function Set-InstallationProcess
{
    <#
    .SYNOPSIS
    This will set the installation process
    .DESCRIPTION
    The installation process is stored in a file,
    this will set the current status of the installation
   .EXAMPLE
    .\Set-InstallationProcess -File "C:\InstallationProcess.txt" -Value 1
    #>
    Param(
        [string]$File=$cfg['installationprocessfile'],
        [Parameter(Mandatory=$True)][int]$Value
    )
    Try {
        Set-Content $File -Value $Value -ErrorAction Stop;
    }
    Catch{
        Log-Write "Could not set the installation process because of $_";

        Exit;
    }
}


Function Set-IEESC
{
    <#
    .SYNOPSIS
    With this you can enable or disable the Security of IEESC
    .DESCRIPTION
    This will enable/disable Internet Explorer Enhanced Security Configuration,
    Internet Explorer Enhanced Security Configuration established a configuration
    for your server and for Microsoft Internet Explorer that decreases the exposure
    of your server to potential attacks that can occur through Web content and
    application scripts. As a result, some Web sites may not display or perform
    as expected.
   .EXAMPLE
    .\Set-InstallationProcess -File "C:\InstallationProcess.txt" -Value 1
    #>
    Param(
        [ValidateSet("On", "Off")]$Mode="On"
    )
    $Value = if ($Mode -eq "On") { 1 } else { 0 }
    Try{
        $AdminKey = “HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}”;

        $UserKey = “HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A8-37EF-4b3f-8CFC-4F3A74704073}”;

        Set-ItemProperty -Path $AdminKey -Name “IsInstalled” -Value $Value -ErrorAction Stop;

        Set-ItemProperty -Path $UserKey -Name “IsInstalled” -Value $Value -ErrorAction Stop;

        Log-Write “Internet Explorer Enhanced Security Configuration (IE ESC) has been set to mode: $Mode.”;
    }
    Catch{
        Log-Write "Failed to set the Internet Explorer Enhanced Security Configuration to mode: $Mode because of: $_";
    }
}


Function Set-LocaleLanguageToSwedish
{
    <#
    .SYNOPSIS
    Sets the language to swedish so that the keyboard in office works.
    .DESCRIPTION
    This will set the default keyboard language of the server to swedish.
    #>

    $locale = @{
        "Locale"="00000409";          "LocaleName"="sv-SE";           "s1159"=""; 
        "s2359"="";                   "sCountry"="Sweden";            "sCurrency"="kr";
        "sDate"="-";                  "sDecimal"=",";                 "sGrouping"="3;0";
        "sLanguage"="SVE";            "sList"=";";                    "sLongDate"="'den 'd MMMM yyyy";
        "sMonDecimalSep"=",";         "sMonGrouping"="3;0";           "sMonThousandSep"="."; 
        "sNativeDigits"="0123456789"; "sNegativeSign"="-";            "sPositiveSign"="";
        "sShortDate"="yyyy-MM-dd";    "sThousand"=" ";                "sTime"=":";
        "sTimeFormat"="HH:mm:ss";     "sShortTime"="HH:mm";           "sYearMonth"="MMMM yyyy";
        "iCalendarType"="1";          "iCountry"="46";                "iCurrDigits"="2"; 
        "iCurrency"="3";              "iDate"="2";                    "iDigits"="2"; 
        "NumShape"="1";               "iFirstDayOfWeek"="0";          "iFirstWeekOfYear"="2";
        "iLZero"="1";                 "iMeasure"="0";                 "iNegCurr"="8";
        "iNegNumber"="1";             "iPaperSize"="9";               "iTime"="1";
        "iTimePrefix"="0";            "iTLZero"="1";
    }

    Try{
        $locale.GetEnumerator() | % { 
            Set-ItemProperty -Path "HKCU:\Control Panel\International" -Name $_.key -Value $_.value -ErrorAction Stop;
        }
        Set-ItemProperty -Path "HKCU:\Control Panel\International\Geo" -Name "Nation" -Value '221' -ErrorAction Ignore;

        Set-WinUserLanguageList -LanguageList sv-SE -Force;

        Log-Write "locale settings have been changed and the language is set to swedish. currency to kr, as well as the use of decimal istead of '.'";
    }
    Catch {
        Log-Write "failed to set the locale settings because of $_";
    }
}

Function Set-TimeZone
{
    <#
    .SYNOPSIS
    Sets the timezone to Europe
    .DESCRIPTION
    This will set the timezone to Europe so its not using
    UnitedStates timezone settings.
    .EXAMPLE
    .\Set-TimeZone -Zone "W. Europe Standard Time"
    #>
    Param(
        [Parameter(Mandatory=$True)][String]$Zone
    )
    Try{
        $Null = Invoke-Expression $('tzutil /s "'+$Zone+'"') -ErrorAction Stop;

        Log-Write "Server timezone set to: $Zone.";
    }
    Catch{
        Log-Write "Failed to set server timezone to: $Zone. because of: $_";
    }
   
}

Function Set-NtpServer
{
    <#
    .SYNOPSIS
    This will set the servers ntp server
    .DESCRIPTION
    In order to have a unified timestamp on all events
    this will set the server to connect to a specific ntp server.
    .EXAMPLE
    .\Set-NtpServer -Server "ntpserver.time.com"
    #>
    Param(
        [Parameter(Mandatory=$True)][String]$Server
    )
    Try{
        w32tm /config /manualpeerlist:$Server /syncfromflags:MANUAL

        Stop-Service w32time;

        Start-Service w32time;

        Log-Write "ntp server has been set to $Server";
    }
    Catch{
       Log-Write "Something went wrong when trying to se the ntpserver, error: $_";
    }
    
}

Function Set-WindowsFirewall
{
    <#
    .SYNOPSIS
    This will Disable the firewall
    .DESCRIPTION
    This will Disable the firewall on the machine.
    .EXAMPLE
    .\Set-WindowsFirewall -Mode On
    #>
    Param(
        [ValidateSet("On", "Off")]$Mode="On"
    )
    Try{
        $Null = Invoke-Expression "netsh advfirewall set allprofiles state $Mode" -ErrorAction Stop;

        Log-Write "Windows Firewall has been set to $Mode.";
    }
    Catch{
        Log-Write "Failed to set mode $Mode on the Windows Firewall because of: $_";
    }
}

Function Set-AudioService
{
    <#
    .SYNOPSIS
    This will Start the Audio Service
    .DESCRIPTION
    This will Start the Audio Service and also
    make it run each boot.
    .EXAMPLE
    .\Set-AudioService -Mode On
    #>
    Param(
        [ValidateSet("On", "Off")]$Mode="On"
    )
    Try
    {
        If ($Mode -eq "On")
        {
            $Value = "Automatic";

            Start-Service AudioSrv -ErrorAction Stop;
        } else {
            $Value = "Manual";

            Stop-Service AudioSrv -ErrorAction Stop;

        }
        Set-Service AudioSrv -startuptype $Value -ErrorAction Stop;

        Log-Write "Windows Audio has been set to $Value."
    }
    Catch
    {
        Log-Write "Failed to change Windows Audio because of: $_.";
    }
}

Function Set-WindowsUpdate
{
    <#
    .SYNOPSIS
    Set windows update level 1-4
    .DESCRIPTION
    Set the windows update level for how the server should
    handle windows updates.
    # Notification Level 1 is ~Never check for updates~
    # Notification Level 2 is ~Check for updates but let me choose whether to download and install them~ 
    # Notification Level 3 is ~Download updates but let me choose whether to install them~
    # Notification Level 4 is ~Install updates automatically~
    .EXAMPLE
    .\Download-Files -Path  -Destination C:\Scripts\Downloads\
    #>
    Param(
        [Parameter(Mandatory=$True)][ValidateRange(1,4)][int]$Level
    )
    Log-Write "configuring windows updates";
    Try{

	    $objAutoUpdate =New-Object -ComObject "Microsoft.Update.AutoUpdate";

	    $objSett = $objAutoUpdate.Settings;

	    $objSett.NotificationLevel = $Level;

	    $objSett.Save();

        Switch($Level) 
        { 
            1 {$Note = 'Never check for updates'; }

            2 {$Note = 'Check for updates but let me choose whether to download and install them';}

            3 {$Note = 'Download updates but let me choose whether to install them';}

            4 {$Note = 'Install updates automatically'; }
        }
	    Log-Write "Windows Updates set to: $Note.";
    }
    Catch{
	    Log-Write "Failed to set Windows Updates to: $Note. because of: $_";
    }
}

Function Download-Files
{
    <#
    .SYNOPSIS
    Downloads the installationfiles to the localmachine.
    .DESCRIPTION
    Downloads Specified Files to the local machine.
    .EXAMPLE
    .\Download-Files -Path  -Destination C:\Scripts\Downloads\
    #>
    Param(
        [string]$Path=$cfg['external_file_server'],
        [string]$Destination=$cfg['download_file_path']
    )
   If (!(Test-Path $Destination))
   {
       $NULL = New-Item $Destination -type directory -Force -ErrorAction Stop
   }

   If((Test-Path $Path))
   {
        Log-Write "download started from: $Path"
        
        Copy-Item -Path $Path -Destination $Destination -Force -ErrorAction Stop -Recurse
        
        Log-Write "download completed to: $Destination"
   }
}

Function Set-NvidiaCardMode
{
    <#
    .SYNOPSIS
    Set the Nvidia Driver to TCC mode or WDDM mode.
    .DESCRIPTION
    Set the Nvidia Driver to TCC mode or WDDM mode.
    TCC mode will use the graphics card as a computing
    power for enhanced calculations while WDDM uses it for graphics.
    .EXAMPLE
    .\NvidiaCardMode -EnableTCC 1
    The above example would have put the card into TCC mode.
    #>
    Param(
        [Parameter(Mandatory=$True)][ValidateRange(0,1)][int]$EnableTCC
    )
        $File = "C:\Program Files\NVIDIA Corporation\NVSMI\nvidia-smi.exe";
        
        if((Test-Path $File))
        {
            $TCC = Invoke-Expression "& '$File' -i 0 -fdm $EnableTCC";
            
            if($TCC -match "Error")
            {
                Log-Write "*** ERROR - $TCC";
            }
            else
            {
                Log-Write "*** SUCCESS - $TCC";
            }
        }
        else
        {
            Log-Write "ERROR *** nvidia-smi.exe not found / installed!"
            #Exit;
        }
}



Function Remove-ZoneIdentifiers
{
    <#
    .SYNOPSIS
    This function will remove the protection from downloaded files.
    .DESCRIPTION
    In order to execute files downloaded from the web through script
    the Zone Identifier has to be neutrilized this function does just
    that.
    .EXAMPLE
    .\Remove-ZoneIdentifiers -Paths @('C:\MyDownloadedFiles','C:\SomeOtherTempFolder')
    This example would install "WHATEVER.exe" in quiet mode and repair etc..
    #>
    Param(
        [Parameter(Mandatory=$True)][array]$Paths
    )
    foreach ($Path in $Paths)
    {
        & cmd.exe /c "dir `"$Path`" /r && exit 0 || exit 1" | 
            Where { $_ -match "Zone.Identifier" } | 
                ForEach-Object `
                { 
                    $filename = $_.trimstart(' ').trimstart('1234567890').trimstart(' ').trimend(':$DATA');

                    Log-Write "*** ZONE FILE Detected: $filename, trying to remove zone info."

                    & cmd.exe /c "echo.>`"$($Path)\$filename`" && exit 0 || exit 1";
                }
    }
}

Function Install-Application
{
    <#
    .SYNOPSIS
    This function will install an application specified.
    .DESCRIPTION
    This function will install a given application on the localhost,
    the user has to be administrator on the computer and powershell
    has to be run in elevated mode.
    .EXAMPLE
    .\Install-Application WHATEVER.exe -Arg '/quiet /silent /repair'
    This example would install "WHATEVER.exe" in quiet mode and repair etc..
    #>

    Param(
        [Parameter(Mandatory=$True)][string]$Application, 
        [string]$Arg='/s /v /qb',
        [switch]$NoRunAs=$FALSE,
        [Array][email protected]('0'),
        [string]$CustomName
    )
    

    Sleep 2;

    if(Test-Path $Application)
    {
        $applicationinfo = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($Application)
        
        if((Check-ifInstalled -Path $Application -Method Read) -eq $False)
        {

            Log-Write "installing $($applicationinfo.ProductName) version: $($applicationinfo.ProductVersion)"
                
            if (($NoRunAs))
            {
                $setup=Start-Process $Application -ArgumentList $Arg -Wait -PassThru
            }
            else
            {
                $setup=Start-Process $Application -ArgumentList $Arg -Wait -PassThru -Verb RunAs
            }

            if($CustomName)
            {
                $ApplicationName = $CustomName;
            } else {
                $ApplicationName = $applicationinfo.ProductName
            }
        
            if ($AcceptedExitCodes -contains $setup.exitcode)
            {
                Log-Write "Successfully installed $($ApplicationName)!"
                Check-ifInstalled -Path $Application -Method Write -Verdict Installed;
            }
            else
            {
                Log-Write "Installation failed with exitcode: $($setup.exitcode) for: $($ApplicationName)!"
                Check-ifInstalled -Path $Application -Method Write -Verdict Failed;
            }
        } else {
            Log-Write "application is already installed skipping..."
        } 
    } else {
        Log-Write "Note *** application '$Application' can't be found, please check!! Exiting."
        Exit;
    }
}

Function Check-ifInstalled {
    <#
    .SYNOPSIS
    This function will check if an application has already installed
    .DESCRIPTION
    This function will check if an application has already installed
    if the script has been run multiple times, and skip the ones
    which have been successfull.
    .EXAMPLE
    .\Check-ifInstalled -Path "C\myapplication.exe" -Method Read
    This example would check if the application "myapplication" has been installed already.
    .\Check-ifInstalled -Path $Application -Method Write -Verdict Installed;
    This example would write to file wether an application was installed succesfully.
    #>
    Param(
        [Parameter(Mandatory=$True)][String]$Path,
        [ValidateSet('Read','Write')][String]$Method="Read",
        [ValidateSet('Failed','Installed')][String]$Verdict
    )
    $progress_path = "$($cfg['log_path'])rbik_installation_progress.log";
    Try{
        If(!(Test-Path $progress_path)){
            New-Item -Path $progress_path -ItemType File -Force -ErrorAction Stop;
        }

        If($Method -eq "Read"){

            If ((Get-Content $progress_path) -ne $Null)
            {
                $file = Get-Content $progress_path; 
  
                $counter = 1;

                Foreach($line in $file) {

                    $col = $line.split("|");

                    if($col[2] -eq $Path)
                    {
                        if($col[1] -eq 'Installed'){ return $true; } else { return $false; }
                    }

                    if($counter -eq $file.Count) { return $false }

                    ++$counter;
                }
            } Else { return $false;}
        } Else {
            Add-content $progress_path -value "$(get-date -Format ('yyyy-MM-dd HH:mm:ss'))|$Verdict|$Path" -ErrorAction Stop;
        }
    }
    Catch{
        Log-Write "Warning, could not read/write installation_progress because of $_";
    }

}

Function Create-ScheduledTask   {
    <#
    .SYNOPSIS
    This will help create a new scheduled task.
    .DESCRIPTION
    You can easily create new tasks in order to install items
    has to be run in elevated mode.
    .EXAMPLE
    .\Create-ScheduledTask -TaskName 'My First Task' -TaskRun "'cmd.exe'"
    #>
           
    Param(            
        [string]$ComputerName = "localhost",            
        [string]$RunAsUser = "$($env:computername)\administrator",  #System
        [string]$Password = "yourdefaultpassword",
        [string]$TaskName = "blank",            
        [string]$TaskRun = "'PowerShell.exe -NoLogo -File $($cfg['script'])'",            
        [ValidateSet("MINUTE", "HOURLY", "DAILY", "WEEKLY", "MONTHLY", "ONCE", "ONSTART", "ONLOGON", "ONIDLE")][string]$Schedule = "ONSTART"
    )                            
                                                            
    $Command = "schtasks.exe /create /s $ComputerName /ru $RunAsUser /rp $Password /tn $TaskName /tr $TaskRun /sc $Schedule /F /rl HIGHEST";
            
    $Null = Invoke-Expression $Command;

    Log-Write "task: $TaskName has been created on $ComputerName"
 }

Function Get-ScheduledTask
{
    <#
    .SYNOPSIS
    With this function you can fetch all tasks in an array.
    .DESCRIPTION
    with this you can fetch all tasks currently on the system.
    .EXAMPLE
    .\$arrValues = Get-ScheduledTask -ComputerName 'localhost';
    #>

	Param(
    [string]$ComputerName = "localhost",
    [string]$Task
    )
	Write-Host "Computer: $ComputerName";

	$Command = "schtasks.exe /query /s $ComputerName";

	Invoke-Expression $Command;

	Clear-Variable Command -ErrorAction SilentlyContinue;

	Write-Host "`n";
}

Function Remove-ScheduledTask
{
    <#
    .SYNOPSIS
    With this function you can remove tasks previously created.
    .DESCRIPTION
    With this function you can remove tasks previously created.
    .EXAMPLE
    .\Remove-ScheduledTask -ComputerName 'localhost' -TaskName "TempTask"
    #>

    Param(
        [string]$ComputerName = "localhost",
        [string]$TaskName = "blank"
    )
    If ((Get-ScheduledTask -ComputerName $ComputerName) -match $TaskName)
	{
		$Command = "schtasks.exe /delete /s $ComputerName /tn $TaskName /F";

		$Null = Invoke-Expression $Command;

		Clear-Variable Command -ErrorAction SilentlyContinue;

        Log-Write "task: $TaskName has been removed on $ComputerName"
	}
    Else
	{
		    Log-Write "task: $TaskName was not found on $ComputerName"
	}
}


Function Check-Elevation
{
    <#
    .SYNOPSIS
    This function checks if user is running powershell in elevated mode.
    .DESCRIPTION
    This function checks if user is running powershell in administartor role
    as it needs to edit system settings.
    .EXAMPLE
    .\Check-Elevation
    This will prompt and exit the powershell script if you are not in elevated mode.
    #>
    
    $myIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent();

    $wp = New-Object Security.Principal.WindowsPrincipal($myIdentity);

    if (-not $wp.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator))
    {
        Log-Write "This script requires administrative privileges, please re-launch with elevated credentials";
        Exit;
    }
}

Function Create-Admin-User
{
    <#
    .SYNOPSIS
    Create a new admin user on the local machine.
    .DESCRIPTION
    You can easily create a new admin account on the local machine.
    .EXAMPLE
    .\Create-Admin-User -Username "Admin" -Password "MyNewPassword" -NeverExpire $true;
    #>
    Param(
        [Parameter(Mandatory=$true)][String]$Username,
        [Parameter(Mandatory=$true)][String]$Password,
        [Parameter(Mandatory=$true)][String][Switch]$NeverExpire
    )

    Log-Write "Trying to add user $Username";
    if(!(gwmi -class Win32_UserAccount | Where {$_.Name -eq "$Username"}))
    {
        Try {
            
            NET USER $Username "$Password" /ADD

            NET LOCALGROUP "Administrators" "$Username" /add

            if($NeverExpire -eq $TRUE ){
                WMIC USERACCOUNT WHERE "Name='$Username'" SET PasswordExpires=FALSE
            }

            if((gwmi -class Win32_UserAccount | Where {$_.Name -eq "$Username"})){

                Log-Write "successfully created user $Username";
            }
        }
        Catch {
            Log-Write "adding new user $Username failed because: $_";
        }
    } else {
        Log-Write "User $Username already exists, skipping creation of account...";
    }
}


Function Unzip-File
{
    <#
    .SYNOPSIS
    Unzip a zip file
    .DESCRIPTION
    You can easily unzip a zip file using this function
    to any destination specified.
    .EXAMPLE
    .\Unzip-File -File "C:\Temp\Myzip.zip" -Destination "C:\Users\MyUser\Desktop\MyZip";
    #>

    Param(
        [Parameter(Mandatory=$True)][string]$File,
        [string]$Destination=$cfg['download_file_path']
    )
    Try{
        if (!(test-path $File)) { throw "$File does not exist"; exit; }

        if (!(test-path $Destination)) { New-Item -Path $Destination -ItemType Directory -Force } 

        $Shell = new-object -com shell.application;

        $Shell.namespace($Destination).copyhere( $shell.namespace($file).items() );
    }
    Catch {
        Log-Write "Failed to unzip the zipfile because of: $_";
    }

}

Function Enable-DesktopExperience
{
    <#
    .SYNOPSIS
    Enables Desktop Experience
    .DESCRIPTION
    This Enables desktop experience, note that this requires a reboot.
    #>

   Try
    {
        Import-Module ServerManager -ErrorAction Stop;

        Add-WindowsFeature Desktop-Experience -IncludeAllSubFeature;

        Log-Write "Enabling desktop experience";
    }
    Catch
    {
        Log-Write "Failed to enable desktop experience because $_";
    }
}

Function Set-AutoLogin
{
    <#
    .SYNOPSIS
    Will set a local account to autologin on the computer.
    .DESCRIPTION
    This will help set a local account to login automatically
    on the local machine.
    .EXAMPLE
    .\Set-AutoLogin 
    #>
    Param(
        [Parameter(Mandatory=$true)][ValidateSet("On", "Off")]$Mode,
        [String]$Username=$False,
        [String]$Password=$False

    )

    If ($Mode -eq "On" -and $Username -and $Password)
    { 
        $Value = "1"; $DefaultUsername = "localhost\$Username"; $DefaultPassword = "$Password";

        Log-Write "Enabling autologin for account: $Username";
    } else {
        $Value = "0"; $DefaultUsername = ""; $DefaultPassword = "";

        Log-Write "Disabling admin auto login on the machine.";
    }

    $RegPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon";
    
    Try {
        Set-ItemProperty $RegPath "AutoAdminLogon" -Value $Value -type String -ErrorAction Stop;

        Set-ItemProperty $RegPath "DefaultUsername" -Value $DefaultUsername -type String -ErrorAction Stop;

        Set-ItemProperty $RegPath "DefaultPassword" -Value $DefaultPassword -type String -ErrorAction Stop;
    }
    Catch {
        Log-Write "Failed to set mode: $Mode for Autologin because: $_";
    }
}

Function Create-Shortcut
{
    <#
    .SYNOPSIS
    This function create a shortcut
    .DESCRIPTION
    This function will let you create a shortcut to a file or folder
    log entries to a log file.
    .EXAMPLE
    .\Create-Shortcut -SourceExe 'C:\MyFile.exe' -Name 'SuperMario' -Path 'H:\Users\UserAccount\Desktop'
    In this example A shortcut would have been created for MyFile.exe which resides in C:\ and placed on the Desktop.
    #>
    Param ( 
        [Parameter(Mandatory=$true)][string]$SourceExe, 
        [Parameter(Mandatory=$true)][string]$Destination,
        [Parameter(Mandatory=$true)][string]$Name
    )

    if(Test-Path $SourceExe)
    {
        Log-Write "Creating shortcut $Destination\$Name to: $SourceExe";

        $WshShell = New-Object -comObject WScript.Shell;

        $Shortcut = $WshShell.CreateShortcut("$Destination\$Name.lnk");

        $Shortcut.TargetPath = $SourceExe;

        $Shortcut.Save();

        if(!(Test-Path "$Destination\$Name.lnk")){
            Log-Write "Failed to create shortcut to $Destination\$Name for: $SourceExe";
        }
    } else {
        Log-Write "Shortcut $Destination\$Name could not be created as Source($SourceExe) was not found";
    }
}

 

And for the main script which initializes all the functions


<#
 .SYNOPSIS
 This script will install all the prerequisites on a server automatically
 .DESCRIPTION
 It will not function without it's functional package called installaton_functions.ps1

     Date Created: 2016-04-08

 .EXAMPLE
 Run the script as Administrator
 .\scriptName.ps1 -Start y;
 The example above would run the script automatically.
#>
Param([String]$Start)
echo $Start;
$PSScriptRoot = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition
$PSScriptName = $MyInvocation.MyCommand.Definition;

######################################################################################
####### --- SCRIPT GLOBAL SETTINGS --- ###############################################
######################################################################################

$cfg = @{
    log_path                 = 'C:\Script\Logs\initialize-server\'
    script                   = "$($PSScriptName)"
    external_file_server     = '\\YourFileServer\c$\somedirectory\*'
    download_file_path       = 'c:\Script\Temp\'
    zipped_packet            = "$($PSScriptRoot)\DATA.zip"
    script_task_name         = 'initialize-server'
    user_username            = 'localadministratoraccount'
    user_password            = 'localadministratorpassword!'
    function_script        = "$PSScriptRoot\powershell_repository\installation_functions.ps1"
}
$cfg += @{
    installationprocessfile = $cfg['log_path']+"progress.txt"
    log_name                = 'Server-Prep.log'
}


# Echo Config
echo $cfg;

######################################################################################
######################################################################################
######################################################################################

# Autorun script or not.
While($Start -notmatch "y|n"){
    $Start = Read-Host('Do you want to proceed? (y/n)');
}

If ($Start -match "n") { Exit; }


# Import All Functions required by the script.
if((Test-Path -Path $($cfg['function_script'])))
{
  . $($cfg['function_script']);
} else {
  Write-Host "FATAL ERROR!! Functional Script ($($cfg['function_script'])) is not present, Exiting..." -BackgroundColor DarkRed;
  Exit;
}

$Progress = Get-InstallationProcess;
if($Progress -like "0")
{
    Log-Write "Starting new installation!";
}




Switch ($Progress) 
{
        ######################################################################################
    0 {

        # Check if script is run with Admin Privileges. 
        Check-Elevation
        
        # Create the Admin Account used by the Razorbox application.
        Create-Admin-User -Username $cfg['user_username'] -Password $cfg['user_password'] -NeverExpire $True;

        # Create a scheduled task for the installation.
        Create-ScheduledTask -TaskName $cfg['script_task_name'] -RunAsUser "$($env:computername)\$($cfg['user_username'])" -Password $cfg['user_password'] -Schedule ONSTART -ComputerName "localhost" -TaskRun "'PowerShell.exe -NoLogo -File $($cfg['script'])'";

        # Sets Automatic login for an account used while the installation 
        # is progressing in case any interactive prompts occur.
        Set-AutoLogin -Mode On -Username $cfg['user_username'] -Password $cfg['user_password'];

        # Sets the keyboard to Swedish and also the currency to swedish.
        Set-LocaleLanguageToSwedish;

        # Set the server timezone.
        Set-TimeZone -Zone "W. Europe Standard Time";

        # Disable Windows firewall
        Set-WindowsFirewall -Mode Off;

        # Disable Internet Explorer Enhanced Security Configuration
        Set-IEESC -Mode Off; 

        # Enable Windows Audio Service 
        Set-AudioService -Mode On;

        #3 is ~Download updates but let me choose whether to install them~
		Set-WindowsUpdate -Level 3;
            

        if(!(Test-Path -Path "$($cfg['download_file_path'])\DATA"))
        { 
            # Unzip zipped Package
            Unzip-File $($cfg['zipped_packet']);

            # Unblock DownloadedFiles.
            Remove-ZoneIdentifiers -Paths @($cfg['download_file_path'], "$($cfg['download_file_path'])Programs\Prerequisites\DirectX10");
        }

        # Enable Desktop Experience
        Enable-DesktopExperience;

        # Install DirectX10
        Install-Application "$($cfg['download_file_path'])DATA\Programs\Prerequisites\DirectX10\DXSETUP.exe" -Arg "/silent";
            
        # Microsoft Visual C++ 2010 Redistributable 
        Install-Application "$($cfg['download_file_path'])DATA\Programs\Prerequisites\VC2010\vcredist_x86_2010.exe" -Arg '/q /norestart';

        # Microsoft Visual C++ 2012 Redistributable 
        Install-Application "$($cfg['download_file_path'])DATA\Programs\Prerequisites\VC2012\vcredist_x86_2012.exe" -Arg '/q /norestart';

        # Microsoft Visual C++ 2013 Redistributable 
        Install-Application "$($cfg['download_file_path'])DATA\Programs\Prerequisites\VC2013\vcredist_x86_2013.exe" -Arg '/q /norestart';
             
        # Install dotNET 4.5.1
        Install-Application "$($cfg['download_file_path'])DATA\Programs\Prerequisites\DotNet45\dotNetFx45_Full_setup.exe" -Arg "/q /norestart" -AcceptedExitCodes @('0','1641','3010')

        # Nvidia Quadro Tesla Desktop Driver
        Install-Application "$($cfg['download_file_path'])DATA\Programs\Prerequisites\NvidiaDriverK4200-v.341.21.x64\setup.exe" -Arg "-s -noreboot -clean -noeula";

        Set-InstallationProcess -Value "1";

        Log-Write "Restarting server...";

        Restart-Computer -Force;
      }
        ######################################################################################
    1 {
        Log-Write "Server has booted... beginning second steps";

        Sleep 10;

        # Force Enable TCC Mode on graphics card.
        Set-NvidiaCardMode -EnableTCC 1;
                 
        Set-InstallationProcess -Value "2";
        Log-Write "restarting server... *** BIOS *** Change Videocard settings in bios if server is a HP 2U Proliant Gen 9 - Embedded as Primary ***";
            
        Restart-Computer -Force;
      }
        ######################################################################################
    2 {
        # Set-InstallationProcess -Value "3"
        Log-Write "Server has booted... beginning third steps";
 
 
        # Nvidia CUDA Drivers
        Install-Application "$($cfg['download_file_path'])DATA\Programs\Prerequisites\NvidiaCuda\cuda_6.5.14_x64.exe" -Arg "-s -n";

        # Remove AutoLogin
        Set-AutoLogin -Mode Off;

            # Update Install Process
        Set-InstallationProcess -Value "3";


        Log-Write "You need to restart after Blackmagic card has been installed.!"

            
        #Restart-Computer
    }
        ######################################################################################
    3 {
        Remove-ScheduledTask -TaskName $cfg['script_task_name'];

        Log-Write "Installation complete!";
        Log-Write "-------------------------------------------------------------------------" -NoDate

    } 
    default { Log-Write "Progress Could not be determined!"}
}

 

Posted on: Sunday 31 July 2016