Last active
July 13, 2018 23:01
-
-
Save arkag/5d519a97c73c15ff65c4df3194f595d9 to your computer and use it in GitHub Desktop.
Install some basic applications and configurations for all machines.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [CmdletBinding(DefaultParameterSetName = 'Set1')] | |
| Param( | |
| [Parameter(Mandatory, ParameterSetName = 'Set1')] | |
| # Currently doesn't support 365 silent installers | |
| [ValidateSet('2016OL'<#,'365IM','365MS'#>)] | |
| [String]$Office, | |
| [Parameter(Mandatory, ParameterSetName = 'Set2')] | |
| [Switch]$NoOffice, | |
| [Parameter(Mandatory)] | |
| [String]$Name, | |
| [Switch]$InstallDrivers | |
| ) | |
| $drive = Get-CimInstance -ClassName Win32_Volume -Filter "Label='Capuchin'" | |
| $driveLetter = $drive.Name | |
| $admin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") | |
| if (!$admin) { | |
| Write-Host "I need Administrative rights, please accept the UAC." | |
| Start-Sleep -Seconds 1.5 | |
| foreach ($key in $PSBoundParameters.keys) { | |
| $args += "-$key " + $PSBoundParameters["$key"] | |
| } | |
| Start-Process powershell.exe -Wait -Verb runAs -ArgumentList "$driveLetter\Bootstrap.ps1 $args" | |
| Exit | |
| } | |
| function Write-Verbln { | |
| [CmdletBinding()] | |
| Param ([String]$Sentence) | |
| Write-Verbose -Message $Sentence | |
| Write-Verbose -Message "---------`n" | |
| } | |
| $tmp = "C:\tmp" | |
| Write-Verbln "Drive detected as: $driveLetter" | |
| $computer = Get-CimInstance Win32_ComputerSystem | |
| $computerModel = $computer.Model | |
| Write-Verbln "Computer model detected as: $computerModel" | |
| if (!$NoOffice) { | |
| $officeExecutable = "$tmp\$Office\setup.exe" | |
| $officeConfig = "$tmp\$Office\configuration.xml" | |
| } | |
| Write-Host "Bootstrapping..." | |
| Start-Transcript -Path "$driveLetter\logs\$Name-Log.txt" | |
| Write-Verbln "Copying data to $tmp." | |
| Copy-Item -Path $driveLetter\bin -Destination $tmp -Force -Recurse | |
| Write-Verbln "$($driveLetter)bin copied to $tmp." | |
| if ($InstallDrivers -and (Test-Path $tmp\$computerModel)) { | |
| $drivers = Get-ChildItem $tmp\$computerModel | |
| foreach ($d in $drivers.Name) { | |
| Write-Verbose -Message "Installing $d Driver" | |
| Start-Process -FilePath $tmp\$computerModel\$d -ArgumentList /s -Wait | |
| } | |
| Write-Verbln "`tDone" | |
| } | |
| else { | |
| Write-Error "The drivers for your $computerModel are not in $tmp, please download them and place them under a folder named `"$ComputerModel`" before passing the -InstallDrivers flag." | |
| Start-Sleep -Seconds 1 | |
| } | |
| $files = Get-ChildItem $tmp | |
| foreach ($n in $files.Name) { | |
| Write-Verbose "Installing $n..." | |
| switch -Wildcard ($n) { | |
| "*.msi" {Start-Process -Wait -FilePath "$tmp\$n" -ArgumentList /quiet} | |
| "AGENT*" {Start-Process -Wait -FilePath "$tmp\$n" -ArgumentList /VERYSILENT} | |
| "Firefox*" { | |
| Write-Verbose -Message "Downloading Newest Installer" | |
| Invoke-WebRequest -Uri "https://download.mozilla.org/?product=firefox-latest-ssl&os=win64&lang=en-US" -OutFile "$tmp\bin\FirefoxInstaller.exe" | |
| Write-Verbose -Message "Copying Newest installer to flashdrive" | |
| Copy-Item -Path "$tmp\bin\FirefoxInstaller.exe" -Destination $driveLetter\bin -Force -Recurse | |
| Start-Process -Wait -FilePath "$tmp\$n" -ArgumentList -ms | |
| } | |
| "Systems-*" {Start-Process -Wait -FilePath "$tmp\$n" -ArgumentList /s} | |
| $Office {Start-Process -FilePath $officeExecutable -ArgumentList "/config $officeConfig" -Wait} | |
| } | |
| Write-Verbln "`tDone" | |
| } | |
| Rename-Computer -NewName $Name | |
| Write-Host "I've finished initial setup for this machine." | |
| Write-Host "Restarting in 5 seconds..." | |
| Start-Sleep -Seconds 5 | |
| Restart-Computer |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Read-Host probably isn't the best choice. Best to just use
pauseif you need that.Probably want to apply
[CmdletBinding()]and type it as a string parameter.Either
function{param()}orfunction(){}, not both. Pretty sure PS would just complain about it, but best to remove it either way.If this works, you're lucky. $_ isn't valid in this context, so it's probably being read as $null (uninitialised). Shouldn't need it there.
You also have a bunch of Read-Host prompts, which... should generally be avoided. Most, if not all of these can be script parameters, and should be. The things you want user confirmation on should implement
$PSCmdlet.ShouldProcess()or.ShouldContinue()as appropriate for proper y/n/a/na prompts. Multiple choice selects can be done withOut-GridView -OutputMode [Single|Multiple]much more effectively and with less hassle.The installer executions could be pulled into a separate function to facilitate easier error handling and more sophisticated handling of the installations -- or you could look into using Chocolatey.
As a general rule, a good script should have minimal user interaction, and provide parameters such that if you want to run it with none it works flawlessly. It also should also use Write-Verbose instead of Write-Host in most places, if not all, and implement
[CmdletBinding()]in order to make proper use of it. Use of[CmdletBinding(SupportsShouldProcess)]can be used to enable$PSCmdlet.ShouldProcess()as mentioned above.It's also a good idea to get in the habit of building useful output objects and outputting most if not all of your data with them. This allows you to capture and make use of the output. For example, if you kept track of: applications installed, computer name changes, errors encountered, you could capture the script output and filter for (for example) computers that the script failed to fix in a neat little table that shows you exactly what failed for which machines, without scrolling through what would probably end up being hundreds of pages of not strictly necessary write-host babble if you had to run the script against a bunch of machines.
Speaking of, implement proper pipeline support. Nothing better than a
Get-Content ComputerList.txt | Do-AllTheThingsand sit back and sip coffee/tea/water for a good half hour while you go through every computer on the network effortlessly.That's one of the reasons
Write-Hostis so discouraged by a lot of people (myself included) -- you literally cannot suppress it without editing the script. UseWrite-VerboseorWrite-Informationinstead. Sure, they hide their streams by default, but it's easier to tack on a-Verboseswitch than it is to rewrite an entire script because it keeps badgering you with Write-Host.You've also got a lot of
Start-Sleepin here. I get it, it looks nicer. But when you get down to brass tacks, it's going to add a lot of runtime to the script if you're running it more than once or twice, or iterating over pipeline input.