Configure Windows Programmatically

One of the challenges to deploying large windows environments is configuring the individual servers. There are a lot of options available and each one has it’s pros and cons. Unattended answer files are good, but what about when you are using a template to deploy from? vSphere OS Customizations offer a good option as well, but it’s only one piece of the picture. Enter PowerShell.

My goal with this script were to configure very specific items in the Windows OS. I needed to configure the network adapter so that it was renamed, had it’s IP address changed to a static address (with subnet mask, gateway and DNS server). I also wanted to be able to set IESC off, disable Windows Firewall, turn off UAC, set the page file, the timezone, enable Remote Desktop, and a few other things as well.

There’s also a section for setting things up for an AppAssure Core, but I will get into those later.

For now, it comes in three parts. There’s the main script that calls a variables file. Then it creates a shortcut to a script that will join the computer to an AD domain upon reboot. The reboot script will create a shortcut that will cleanup a few things.

Here’s the code for the main script:

<# ======================================================================================================
Purpose: To configure a Windows 2012 Guest.
Author:  Michael Kenning (mjkenning@gmail.com)
Version: 1.33 (15 May 2014)

Notes:  Be sure to change variables in the 2012variables.ps1 file.
  Be sure that VM has NIC plugged in or NIC configuration will fail.
=========================================================================================================
#>

####### FUNCTIONS #######

function Disable-InternetExplorerESC {
    $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 0
    Set-ItemProperty -Path $UserKey -Name "IsInstalled" -Value 0
    Stop-Process -Name Explorer
    Write-Host "IE Enhanced Security Configuration (ESC) has been disabled." -ForegroundColor Green
}
function Enable-InternetExplorerESC {
    $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 1
    Set-ItemProperty -Path $UserKey -Name "IsInstalled" -Value 1
    Stop-Process -Name Explorer
    Write-Host "IE Enhanced Security Configuration (ESC) has been enabled." -ForegroundColor Green
}
function Set-PageFile{
    <#
 .AUTHOR
 Frank Peter (http://www.out-web.net/?p=1109)
 
    .SYNOPSIS
        Sets Page File to custom size
 
    .DESCRIPTION
        Applies the given values for initial and maximum page file size.
 
    .PARAMETER Path
        The page file's fully qualified file name (such as C:\pagefile.sys)
 
    .PARAMETER InitialSize
        The page file's initial size [MB]
 
    .PARAMETER MaximumSize
        The page file's maximum size [MB]
 
    .EXAMPLE
        C:\PS> Set-PageFile "C:\pagefile.sys" 4096 6144
    #>
 
    [CmdletBinding(SupportsShouldProcess=$True)]
    param (
        [Parameter(Mandatory=$true,Position=0)]
        [ValidateNotNullOrEmpty()]
        [String]
        $Path,
        [Parameter(Mandatory=$true,Position=1)]
        [ValidateNotNullOrEmpty()]
        [Int]
        $InitialSize,
        [Parameter(Mandatory=$true,Position=2)]
        [ValidateNotNullOrEmpty()]
        [Int]
        $MaximumSize
    )
     
    Set-PSDebug -Strict
 
    $ComputerSystem = $null
    $CurrentPageFile = $null
    $Modified = $false
 
    # Disables automatically managed page file setting first
    $ComputerSystem = Get-WmiObject -Class Win32_ComputerSystem -EnableAllPrivileges
    if ($ComputerSystem.AutomaticManagedPagefile)
    {
        $ComputerSystem.AutomaticManagedPagefile = $false
        if ($PSCmdlet.ShouldProcess("$($ComputerSystem.Path.Server)", "Disable automatic managed page file"))
        {
            $ComputerSystem.Put()
        }
    }
 
    $CurrentPageFile = Get-WmiObject -Class Win32_PageFileSetting
    if ($CurrentPageFile.Name -eq $Path)
    {
        # Keeps the existing page file
        if ($CurrentPageFile.InitialSize -ne $InitialSize)
        {
            $CurrentPageFile.InitialSize = $InitialSize
            $Modified = $true
        }
        if ($CurrentPageFile.MaximumSize -ne $MaximumSize)
        {
            $CurrentPageFile.MaximumSize = $MaximumSize
            $Modified = $true
        }
        if ($Modified)
        {
            if ($PSCmdlet.ShouldProcess("Page file $Path", "Set initial size to $InitialSize and maximum size to $MaximumSize"))
            {
                $CurrentPageFile.Put()
            }
        }
    }
    else
    {
        # Creates a new page file
        if ($PSCmdlet.ShouldProcess("Page file $($CurrentPageFile.Name)", "Delete old page file"))
        {
            $CurrentPageFile.Delete()
        }
        if ($PSCmdlet.ShouldProcess("Page file $Path", "Set initial size to $InitialSize and maximum size to $MaximumSize"))
        {
            Set-WmiInstance -Class Win32_PageFileSetting -Arguments @{Name=$Path; InitialSize = $InitialSize; MaximumSize = $MaximumSize}
        }
    }
}

####### END FUNCTIONS #######

# Get variables
 try {
 . "C:\2012variables.ps1"
}
catch {
 Write-Warning "Variable file not found. Script execution halted."
 Exit
}
# Start Logging
$ErrorActionPreference="SilentlyContinue"
Stop-Transcript | out-null
$ErrorActionPreference = "Continue"
Start-Transcript -path $logFile | out-null

# Change User Account Control Settings
Set-ItemProperty -Path 'HKLM:Software\Microsoft\Windows\CurrentVersion\policies\system' -Name 'EnableLUA' -Value 0 -ErrorAction SilentlyContinue

# Set Time Zone
tzutil /s $tZone

# Set IP Settings
if ($lanName.GetType().Name -eq "string"){
 # Get Current Network Adapter Name (assuming it's plugged in!)
 $currentNetName = (Get-NetAdapter -physical | where status -eq 'up').name
 
 # Check to make sure the current adapter name doesn't match the new one.
 if ($currentNetName -ne $lanName) {
  $lanStatus = 1
 }
 
 $error.clear()
 try {
  $netadapter = Get-NetAdapter -Name $currentNetName -ErrorAction Stop
 }
 catch {
  Write-warning "Default Network Adapter not found. Skipping network configuration."
 }
 if (!$error) {
  $netadapter | New-NetIPAddress -AddressFamily IPv4 -IPAddress $ipAddress -PrefixLength $subnetPrefix -DefaultGateway $defaultGW
  if ($lanStatus -ne 1) {
   Rename-NetAdapter -Name $currentNetName -NewName $lanName
  }
  Set-DnsClientServerAddress -InterfaceAlias $lanName -ServerAddresses $dnsServer1
 }
}
else {
 Write-Warning "You did not pass a string to the Lan Name variable"
 Exit
}

# Check to make sure the IP Address was assigned
$ipassigned = (get-netadapter | get-netipaddress | ? addressfamily -eq 'IPv4').ipaddress
if ($ipAddress -ne $ipassigned){
 Write-Warning "IP Address not assigned. Please check the configuration file and re-run the script."
 Exit
}

# Firewall Settings
Get-NetFirewallProfile | Set-NetFirewallProfile -Enabled False

# Remote Desktop Settings
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server' -Name fDenyTSConnections -Value 0

# Windows Update Settings
New-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update' -name 'NoAutoUpdate' -value '1' -propertyType "DWord" -force
New-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update' -name 'AUOptions' -value '1' -propertyType "DWord" -force
New-Item 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RequestedAppCategories'
New-Item 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RequestedAppCategories\7971f918-a847-4430-9279-4a52d1efe18d'
New-Item 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RequestedAppCategories\9482f4b4-e343-43b6-b170-9a65bc822c77'

# Disable Internet Explorer ESC
Disable-InternetExplorerESC

# Set Page File Size
Set-PageFile $pageFileLocation $pfInitSize $pfMaxSize

# Set the operating system timeout
bcdedit /timeout 006

# Change the CD-ROM drive letter to Z:\
(gwmi Win32_cdromdrive).drive | %{$a = mountvol $_ /l;mountvol $_ /d;$a = $a.Trim();mountvol z: $a}

# Determine if a Scheduled Task with the name $taskName exists
$taskExists = Get-ScheduledTask -TaskName $taskName *>$null

# Create a scheduled task to reboot the machine
if (!$taskExists){
 if ($aaCore -eq 0){
  $trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Sunday -At $rebootTime
  $settings = New-ScheduledTaskSettingsSet
  Register-ScheduledTask -TaskName $taskName `
          -TaskPath $taskPath `
          -Action $taskAction `
          -Trigger $trigger `
          -User $runAs
 }
 Else {
  
  $trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Sunday -At $rebootTime
  $settings = New-ScheduledTaskSettingsSet
  Register-ScheduledTask -TaskName $taskName `
          -TaskPath $taskPath `
          -Action $taskActionAA `
          -Trigger $trigger `
          -User $runAs
 }
}
Else {
 $trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Sunday -At $rebootTime
 Set-ScheduledTask -Task Name $taskName `
      -TaskPath $taskPath `
      -Action $taskAction `
      -Trigger $trigger `
      -User $runAs
}

# If AA Core, then Create additional scheduled tasks
if ($aaCore -eq 1){
 
 # Shutdown the Core cleanly on demand.
 Remove-variable $taskExists
 $taskExists = Get-ScheduledTask -TaskName $aaShutdownTaskName *>$null
 if (!$taskExists){
  $trigger = New-ScheduledTaskTrigger -Once -At 3am
  $settings = New-ScheduledTaskSettingsSet
  Register-ScheduledTask -TaskName $aaShutdownTaskName `
          -TaskPath $taskPath `
          -Action $aaShutdowntaskAction `
          -Trigger $trigger `
          -User $runAs
 }
 Else {
  
  $trigger = New-ScheduledTaskTrigger -Once -At 3am
  $settings = New-ScheduledTaskSettingsSet
  Set-ScheduledTask -TaskName $aaShutdownTaskName `
         -TaskPath $taskPath `
         -Action $aaShutdowntaskAction `
         -Trigger $trigger `
         -User $runAs
 }
 
 # Resume AA Services, Snapshots and Replication
 Remove-variable $taskExists
 $taskExists = Get-ScheduledTask -TaskName $$aaResumeTaskName *>$null
 if (!$taskExists){
  $trigger = New-ScheduledTaskTrigger -AtStartup
  $settings = New-ScheduledTaskSettingsSet
  Register-ScheduledTask -TaskName $$aaResumeTaskName `
          -TaskPath $taskPath `
          -Action $aaResumeTaskAction `
          -Trigger $trigger `
          -User $runAs
 }
 Else {
  
  $trigger = New-ScheduledTaskTrigger -AtStartup
  $settings = New-ScheduledTaskSettingsSet
  Set-ScheduledTask -TaskName $$aaResumeTaskName `
         -TaskPath $taskPath `
         -Action $aaResumeTaskAction `
         -Trigger $trigger `
         -User $runAs
 }
}
# Rename Computer
Rename-Computer $computerName -ErrorAction Stop

# Create a startup link to the redomain.cmd file and reboot.
$roaming = [environment]::GetFolderPath([environment+specialfolder]::ApplicationData)
$path = "$roaming\Microsoft\Windows\Start Menu\Programs\Startup\redomain.lnk"
$WshShell = New-Object -comObject WScript.Shell
$shortcut = $WshShell.CreateShortcut($path)
$shortcut.TargetPath = "cmd.exe"
$shortcut.Arguments = "/c C:\redomain.cmd"
$shortcut.Save()

Restart-Computer

Here is the code for the redomain.ps1 script:

# Get variables
. "C:\2012variables.ps1"

# Redomain the computer
Add-Computer -DomainName $domainName

# Check to see that the domain was changed
$domainStatus = (gwmi win32_computersystem).partofdomain

# Remove the startup shortcut and reboot
if ($domainStatus -eq $true) {
 # Remove the startup shortcut
 $roaming = [environment]::GetFolderPath([environment+specialfolder]::ApplicationData)
 $path = "$roaming\Microsoft\Windows\Start Menu\Programs\Startup\redomain.lnk"
 Remove-Item $path -confirm:$false
       
 # Turn off autologon as local Temp user
 Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name "AutoAdminLogon"-Value 0
 Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name "DefaultUserName" -Value ""
       
 # Create a startup link to the cleanup.cmd file and reboot.
 ## $roaming = [environment]::GetFolderPath([environment+specialfolder]::ApplicationData)
 $path = "C:\Users\All Users\Start Menu\Programs\StartUp\cleanup.lnk"
 $WshShell = New-Object -comObject WScript.Shell
 $shortcut = $WshShell.CreateShortcut($path)
 $shortcut.TargetPath = "cmd.exe"
 $shortcut.Arguments = "/c C:\cleanup.cmd"
 $shortcut.Save()
     
 Restart-Computer
}
else {
 Write-warning "The domain didn't change."
}

Finally, here is the code for the cleanup script:

# Cleanup the install after running config2012.ps1 #

$hostname = $env:computername
$userName = "Temp"

[ADSI]$myUser="WinNT://$hostname/$userName,User"
[ADSI]$server="WinNT://$hostname"
$server.delete("user",$myUser.name.value)
$path = "C:\Users\All Users\Start Menu\Programs\StartUp\cleanup.lnk"
Remove-Item $path -confirm:$false

If (Test-Path ("C:\Users\All Users\Start Menu\Programs\StartUp\cleanup.lnk")){
 Write-warning "The cleanup shortcut at $path was not deleted. You will need to manually delete the shortcut."
}
Advertisements
Tagged with:
Posted in Powershell

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: