Jump to content

DJ-1701

AFK GNU
  • Posts

    7,556
  • Joined

Blog Entries posted by DJ-1701

  1. DJ-1701
    The following is the latest powershell shortcut deployment script, first shown in http://www.edugeek.net/forums/windows-server-2000-2003/76664-cc3-vanilla-windows-without-wiping-4.html#post1404554
     
    Updates include comment clarification, hiding errors when dealing with files with no shortcut path/MSI generated shortcuts.
     
    Latest script can be found here: https://github.com/DJ-1701/ShortcutDeploy
     
     
     
     
     
     
     
     
     

    # Specify source and destination of shortcut folders below. # **************************************************************************** # * Note: In the source location, create two folders named 32-Bit and 64-Bit * # * to host your Start Menu shortcuts (as shortcut paths may vary). * # **************************************************************************** $Source = "\\ABC-SVR-01\Applications$\StartMenu" $Destination="C:\ProgramData\FolderName\Windows\Start Menu" # Inform user if no Source or Destination has been provided. If (($Source -eq "") -or ($Destination -eq "")) { Write-Host "Missing Source and/or Destination, please check and try again." Exit } # If there is a trailing backslash for $Source and/or $Destination, remove the backslash. If ($Source.Substring($Source.Length-1) -eq "\") { $Source = $Source.Substring(0,$Source.Length-1) } If ($Destination.Substring($Destination.Length-1) -eq "\") { $Destination = $Destination.Substring(0,$Destination.Length-1) } # Update the Source path to include the OS Architecture type to the end of the path. # If no OS Architecture is returned, then use the 32-Bit shortcut folder. $Bit = ((Get-WMIObject Win32_OperatingSystem).OSArchitecture) If ($Bit -eq "") {$Bit = "32-Bit"} $Source = $Source + "\" + $Bit # Inform user if Source does not exist. If (!(Test-Path($Source))) { Write-Host "The Source location does not exist, please check and try again." Exit } # Get the latest last modified date on all shortcuts in Source and Destination paths. $NetworkStamp = Get-ChildItem "$Source\*" -Recurse -Force -include @("*.lnk","*.xml","*.appref-ms")` | Where {!$_.PsIsContainer} | select Name,DirctoryName, LastWriteTime ` | Sort LastWriteTime -descending | select -first 1 $LocalStamp = Get-ChildItem "$Destination\*" -Recurse -Force -include @("*.lnk","*.xml","*.appref-ms") -ErrorAction SilentlyContinue ` | Where {!$_.PsIsContainer} | select Name,DirctoryName, LastWriteTime ` | Sort LastWriteTime -descending | select -first 1 # If there are any differences in the last modified date: # 1) Delete files in Destination (if it exists). # 2) Copy files from Source to Destination. If ($NetworkStamp.LastWriteTime -ne $LocalStamp.LastWriteTime) { If (Test-Path($Destination)) { Remove-Item "$Destination" -Recurse -Force } New-Item -ItemType directory -Path "$Destination" Copy-Item "$Source\*" -Destination "$Destination" -Recurse } # Create a list of folders copied to the destination folder. $ListOfFolders = Get-ChildItem $Destination -Recurse -Force | Where-Object {$_.PSIsContainer} ` | Sort-Object FullName -Descending | % { $_.FullName } # Create a shell object, so we can check if the shortcuts are valid. $sh = New-Object -COM WScript.Shell # Check if Array is Null (Prevents ForEach null bug in PowerShell 2). If ($ListOfFolders -ne $null) { # Do the following for every folder we scanned. FOREACH ($Folder in $ListOfFolders) { # Set the hidden flag to True for the folder. # Note: This will hide the folder later on if applications do not exist. $AllItemsHidden = $true # Get a list of all shortcuts in the current folder. $ListOfShortcuts = Get-ChildItem "$Folder\*" -Force -include *.lnk ` | % { $_.FullName } # Check if Array is Null (Prevents ForEach null bug in PowerShell 2). If ($ListOfShortcuts -ne $null) { # Do the following for every shortcut we scanned. FOREACH ($Shortcut in $ListOfShortcuts) { # Find out if the shortcut is hidden. $Item = Get-Item $Shortcut -Force $CheckHidden = (Get-ItemProperty $Item).Attributes.ToString() -match "Hidden" # Get the target path of the shortcut (the path of the application). # If it refers to C drive (C:), check if it exists, and ensure the shortcut # is visible to the users, otherwise hide the shortcut. $PathOfApplication = $sh.CreateShortcut($Shortcut).TargetPath If ($PathOfApplication.Length -ge 2) { If ($PathOfApplication.Substring(0,2) -eq "C:") { If (Test-Path($PathOfApplication)) { $AllItemsHidden = $false If ($CheckHidden) { $Item.Attributes = $Item.Attributes -bxor [system.IO.FileAttributes]::Hidden } } ElseIf ((!(Test-Path($PathOfApplication))) -and (!($CheckHidden))) { $Item.Attributes = $Item.Attributes -bxor [system.IO.FileAttributes]::Hidden } } } If (($Item.Directory.Name -eq "Programs") -or ($Item.DirectoryName.ToLower().Contains("\Programs\".ToLower()))) { $CheckHidden = (Get-ItemProperty $Item).Attributes.ToString() -match "Hidden" If (!($CheckHidden)) { $Item.Attributes = $Item.Attributes -bxor [system.IO.FileAttributes]::Hidden } } } # List all files in the folder (excluding desktop.ini and thumbs.db, which aren't required). $ListOfSubFilesAndFolders = Get-ChildItem "$Folder\*" -Force -exclude "desktop.ini","thumbs.db" ` | % { $_.FullName } # Check if Array is Null (Prevents ForEach null bug in PowerShell 2). If ($ListOfSubFilesAndFolders -ne $null) { # Do the following for every file or subfolder we scanned. FOREACH ($SubFilesOrFolder in $ListOfSubFilesAndFolders) { # Find out if the file is hidden. If it is not, then it is a required resource. # inform the program not to hide the folder. $Item = Get-Item $SubFilesOrFolder -Force $CheckHidden = $Item.Attributes.ToString() -match "Hidden" If ($CheckHidden -eq $false) { $AllItemsHidden = $false } } } # If all of the files are hidden in the folder, then hide the unrequired folder. # If any file is unhidden in the folder, then unhide the required folder. $Item = Get-Item $Folder -Force $CheckHidden = (Get-ItemProperty $Item).Attributes.ToString() -match "Hidden" If (($AllItemsHidden -and !($CheckHidden)) -or (!($AllItemsHidden) -and $CheckHidden)) { $Item.Attributes = $Item.Attributes -bxor [system.IO.FileAttributes]::Hidden } } If (($Item.Directory.Name -ne $null) -or ($Item.DirectoryName -ne $null)) { If (($Item.Directory.Name -eq "Programs") -or ($Item.DirectoryName.ToLower().Contains("\Programs\".ToLower()))) { $CheckHidden = (Get-ItemProperty $Item).Attributes.ToString() -match "Hidden" If (!($CheckHidden)) { $Item.Attributes = $Item.Attributes -bxor [system.IO.FileAttributes]::Hidden } } } } }
  2. DJ-1701
    Latest version of scripts and information can be found on: https://github.com/DJ-1701/GenerateWallpaper
     
     
     
     
     
     
     
     
     
     
     
     
    Old information below...
     

    The following details shows you how to create Boot and Logon wallpapers using existing wallpaper and adding an overlay of text which can display your school name, computer name, etc via PowerShell scripts which I have created and you may reuse, edit, butcher, etc. .
     
    Examples of this style can be found below:
     
    Boot

     
    Logon

     
    For this exercise we are going to use some pre-created wallpapers for Windows 10 in 19x6 (aka Widescreen) and 4x3 (aka Standard) resolutions, which can be downloaded here.
     
    Extract the zip file to a folder with the School’s name. So, the folder path to both directories should be:
    SchoolName\Wallpaper\4x3
    SchoolName\Wallpaper\19x6
     
    Feel free to have a look at the images in the folder, and delete and add images as you see fit. There are around 280MB worth of images, so you may want to delete some if your machines don’t have much space. After you have finished, copy the SchoolName directory to your Domain Controller’s netlogon share (i.e. \\FQDN\netlogon - where FQDN is the fully qualified domain name for your active directory domain).
     
    Next we are going to take a look at the basic code.
     
    Update Wallpaper

    # Wallpaper folder source. $Domain = (Get-WmiObject -Class Win32_ComputerSystem).Domain $NetworkSource = "\\$Domain\NetLogon\SchoolName\Wallpaper" $LocalSource = "$Env:ProgramFiles\SchoolName\Wallpaper" # Custom wallpaper override file. # Note: Value used to prevent deletion of local file when mirroring. $Override = "$LocalSource\Override.jpg" # Path to robocopy command. $WinDir = (Get-Childitem env:WinDir).Value $Robocopy = "$WinDir\System32\Robocopy.exe" If (!(Test-Path($Robocopy))) { Write-Host "$Robocopy does not exist." Exit } If (!(Test-Path($NetworkSource))) { Write-Host "$NetworkSource does not exist." Exit } If (!(Test-Path($LocalSource))) { New-Item -ItemType directory -Path $LocalSource } # Update local wallpapers. &$Robocopy "$NetworkSource" "$LocalSource" /MIR /XF "$Override" /R:1 /W:1 /NP
     
    Copy and paste the code above into PowerShell ISE, so you can create a PS1 file, and test the code if you so wish.
     
    Please note:

    PowerShell ISE needs to be run as an Administrator for certain aspects of the script to work.
    Rename SchoolName in the script to the actual School Name (i.e. the folder you just copied to you Domain Controller’s netlogon share).

    Save the script as \\FQDN\netlogon\Update Wallpaper.ps1 (where FQDN is the fully qualified domain name for your active directory domain).
     
    When running the script as an Administrator, you should find this will copy the SchoolName folder down from the netlogon share to the C:\Program Files folder on the local computer.
     
    Boot Info

    # Text for the wallpaper. $TextLabel = "School Address Here`r`nTelephone: Telephone Number Here`r`nComputer Name: "+((Get-Childitem env:ComputerName).Value) $TextSizePoint = 18 # Text box colour. $BoxRed = 22 $BoxGreen = 176 $BoxBlue = 221 # Text colour. $TextRed = 255 $TextGreen = 255 $TextBlue = 255 # Wallpaper source folder. $LocalSource = "$Env:ProgramFiles\SchoolName\Wallpaper" # Custom wallpaper override file. $Override = "$LocalSource\Override.jpg" # Completed wallpaper destination location. $WinDir = (Get-Childitem env:WinDir).Value $SystemBackgroundDir = "$WinDir\system32\oobe\info\backgrounds" $DestinationFile = "$SystemBackgroundDir\backgroundDefault.jpg" If (!(Test-Path($LocalSource))) { Write-Host "$LocalSource does not exist." Exit } If (!(Test-Path("$SystemBackgroundDir"))) { New-Item -ItemType directory -Path "$SystemBackgroundDir" } # Find current screen resolution. # Note: Interrogating [system.Windows.Forms.Screen] at boot returns false 1024x768. # Therefore, a separate login script stores this data on user login to a registry key. # After which the PC can check this key. If data does not exist, it will use # recommended supported resolution data. If this fails, it will default to 1024x768. $RegistryPath = "HKLM:\Software\MachineData" If ((Test-Path $RegistryPath)) { If (((Get-ItemProperty -Path $RegistryPath).Horizontal -ne $null) -and ((Get-ItemProperty -Path $RegistryPath).Vertical -ne $null)) { $Horizontal = [int]((Get-ItemProperty -Path $RegistryPath).Horizontal) $Vertical = [int]((Get-ItemProperty -Path $RegistryPath).Vertical) } } If ($Horizontal -eq $null) {$Horizontal = [int]((Get-WmiObject -Class Win32_VideoController).CurrentHorizontalResolution)} If ($Vertical -eq $null) {$Vertical = [int]((Get-WmiObject -Class Win32_VideoController).CurrentVerticalResolution)} If ($Horizontal -eq $null) {$Horizontal = [int]"1024"} If ($Vertical -eq $null) {$Vertical = [int]"768"} If ($Horizontal/$Vertical -le 1.4) { $Ratio = "4x3" } Else { $Ratio = "16x9" } $SourceDir = "$LocalSource\$Ratio" If (!(Test-Path($SourceDir))) { Write-Host "$SourceDir does not exist." Exit } # Select a random file as the source wallpaper. $Files = (dir -Path $SourceDir\* -Recurse).FullName $SourceFile = $Files | Get-Random # If override wallpaper exists, change source file. If ((Test-Path($Override))) { $SourceFile = $Override } # If no source file exists, exit. If (!(Test-Path($SourceFile))) { Write-Host "$SourceFile does not exist." Exit } If ($? -eq $false) { Write-Host "Null Source File." Exit } # Enable the creation of images. Add-Type -AssemblyName System.Drawing # Select a font, size and style. $TextSizePixels=$TextSizePoint/0.75 $Font = New-Object System.Drawing.Font("Arial",$TextSizePixels,[Drawing.FontStyle]'Bold',"Pixel") # Get source image from source file. $SourceImage = [system.Drawing.Image]::FromFile($SourceFile) # Create a new bitmap at the primary monitor resolution to construct an image. $Bitmap = New-Object System.Drawing.Bitmap($Horizontal,$Vertical) # Create image for editing. $Image = [system.Drawing.Graphics]::FromImage($Bitmap) # Ensure the image is clear. $Image.Clear([system.Drawing.Color]::FromArgb(255,255,255,255)) # Set the ARGB values required for the text and text box. $TextARGB = [system.Drawing.Color]::FromArgb(255,$TextRed,$TextGreen,$TextBlue) $BoxARGB = [system.Drawing.Color]::FromArgb(255,$BoxRed,$BoxGreen,$BoxBlue) # Set area for text placement. $Rectangle = [system.Drawing.RectangleF]::FromLTRB(0, 0, $Horizontal, $Vertical) # Set alignment format for the font. $FormatFont = [system.Drawing.StringFormat]::GenericDefault $FormatFont.Alignment = [system.Drawing.StringAlignment]::Center $FormatFont.LineAlignment = [system.Drawing.StringAlignment]::Near # Get text path Layout to work out text box co-ordinates. $TextPath = New-Object System.Drawing.Drawing2D.GraphicsPath $TextPath.AddString($TextLabel,$Font.FontFamily,$Font.Style,$Font.Size,$Rectangle,$FormatFont) # Get co-ordinates of beginning and end of text. $StartX = $Horizontal $StartY = $Vertical $EndX = 0 $EndY = 0 ForEach ($PathPointRow in $TextPath.PathPoints) { If ($PathPointRow.X -le $StartX){$StartX = $PathPointRow.X} If ($PathPointRow.Y -le $StartY){$StartY = $PathPointRow.Y} If ($PathPointRow.X -gt $EndX){$EndX = $PathPointRow.X} If ($PathPointRow.Y -gt $EndY){$EndY = $PathPointRow.Y} } $EndX = $EndX - $StartX $EndY = $EndY - $StartY # Set up the brush colours for drawing text box and text string. $BoxBrushColour = New-Object Drawing.SolidBrush $BoxARGB $TextBrushColour = New-Object Drawing.SolidBrush $TextARGB # Draw image. $Image.DrawImage($SourceImage,0,0, $Horizontal, $Vertical) # Draw box. $Image.FillRectangle($BoxBrushColour,$StartX,$StartY,$EndX,$EndY) # Draw text. $Image.DrawString($TextLabel,$Font,$TextBrushColour,$Rectangle,$FormatFont) # Find last boot time to display on Wallpaper. $TextLabel = "Last Boot: "+((Get-Date).DateTime) # Select a font, size and style. $TextSizePoint = 10 $TextSizePixels=$TextSizePoint/0.75 $Font = New-Object System.Drawing.Font("Arial",$TextSizePoint,[Drawing.FontStyle]'Bold',"Pixel") # Set alignment format for the font. $FormatFont = [system.Drawing.StringFormat]::GenericDefault $FormatFont.Alignment = [system.Drawing.StringAlignment]::Near $FormatFont.LineAlignment = [system.Drawing.StringAlignment]::Far # Get text path Layout to work out text box co-ordinates. $TextPath = New-Object System.Drawing.Drawing2D.GraphicsPath $TextPath.AddString($TextLabel,$Font.FontFamily,$Font.Style,$Font.Size,$Rectangle,$FormatFont) # Get co-ordinates of beginning and end of text, and add padding for text box. $StartX = $Horizontal $StartY = $Vertical $EndX = 0 $EndY = 0 ForEach ($PathPointRow in $TextPath.PathPoints) { If ($PathPointRow.X -le $StartX){$StartX = $PathPointRow.X} If ($PathPointRow.Y -le $StartY){$StartY = $PathPointRow.Y} If ($PathPointRow.X -gt $EndX){$EndX = $PathPointRow.X} If ($PathPointRow.Y -gt $EndY){$EndY = $PathPointRow.Y} } $EndX = $EndX - $StartX + 15 $EndY = $EndY - $StartY + 15 $StartY = $StartY - 5 $StartX = $StartX - 5 # Set up the brush colours for drawing text box and text string. $BoxBrushColour = New-Object Drawing.SolidBrush $BoxARGB $TextBrushColour = New-Object Drawing.SolidBrush $TextARGB # Draw box. $Image.FillRectangle($BoxBrushColour,$StartX,$StartY,$EndX,$EndY) # Draw text. $Image.DrawString($TextLabel,$Font,$TextBrushColour,$Rectangle,$FormatFont) # Save edited bitmap to file. $Bitmap.Save($DestinationFile,[system.Drawing.Imaging.ImageFormat]::Jpeg) # Clean up and remove objects. $SourceImage.Dispose() $Bitmap.Dispose() $Image.Dispose() $SourceDestinationFile # Open saved file. #Invoke-Item $DestinationFile
     
    Copy and paste the code above into PowerShell ISE, so you can create a PS1 file, and test the code if you so wish.
     
    Please note:

    PowerShell ISE needs to be run as an Administrator for certain aspects of the script to work.
    Edit the section after '$TextLabel = "' to change the text which is saved on the wallpaper.
    Rename SchoolName in the script to the actual School Name (i.e. the folder you just copied to you Domain Controller’s netlogon share).

    Save the script as \\FQDN\netlogon\SchoolName\Wallpaper\Boot Info.ps1 (where FQDN is the fully qualified domain name for your active directory domain).
     
    When running the script as an Administrator, you should find this will grab a random file from the correct screen ratio folder (or nearest, if you have a non-standard/old widescreen) generate the text to overlay (so in this case School Address, Telephone Number and Computer Name in the top centre, and the Boot Time in the bottom left) and save the file to C:\Windows\System32\oobe\info\backgrounds\backgroundDefault.jpg.
     
    The reason we are using this location by default is because it is also the standard location Windows 7 looked to for a corporate wallpaper, the path can be changed on Windows 10 if you wish to place it elsewhere.
     
    Please note that the wallpaper will not change until we update group policy to force this new file, but you can view the output in the file mentioned above.
     
    Logon Info

    # Text for the wallpaper. $TextLabel = "School Address Here`r`n`r`nUser Name: "+($env:USERNAME)+"`r`nComputer Name: "+($env:COMPUTERNAME)+"`r`nModel: "+((Get-WmiObject Win32_ComputerSystem).Model)+"`r`nSerial Number: "+((Get-WmiObject Win32_ComputerSystemProduct).IdentifyingNumber) $TextSizePoint = 12 # Text box colour. $BoxRed = 0 $BoxGreen = 125 $BoxBlue = 255 # Text colour. $TextRed = 255 $TextGreen = 255 $TextBlue = 255 # Wallpaper source folder. $LocalSource = "$Env:ProgramFiles\SchoolName\Wallpaper" # Completed wallpaper destination location. $DestinationFile = "$env:temp\LogonInfo.jpg" # Clear theme cache files. Remove-Item -Path "$($env:APPDATA)\Microsoft\Windows\Themes\*" -Recurse -Force -ErrorAction SilentlyContinue # Ensure image is set to Stretch to screen resolution and not tile. Set-ItemProperty -Path 'HKCU:\Control Panel\Desktop' -Name WallpaperStyle -Value "2" -Force Set-ItemProperty -Path 'HKCU:\Control Panel\Desktop' -Name TileWallpaper -Value "0" -Force If (!(Test-Path($LocalSource))) { Write-Host "$LocalSource does not exist." Exit } # Find current screen resolution. # Note: Interrogating [system.Windows.Forms.Screen] at boot returns false 1024x768. # Therefore, this login script stores the data on user login to a registry key. # After which the boot script can check this key. If data does not exist, it will use # recommended supported resolution data. If this fails, it will default to 1024x768. [void] [system.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") $RegistryPath = "HKLM:\Software\MachineData" $Horizontal = [int]([system.Windows.Forms.Screen]::AllScreens[0]).Bounds.Width $Vertical = [int]([system.Windows.Forms.Screen]::AllScreens[0]).Bounds.Height If (!(Test-Path $RegistryPath)) {New-Item -Path $RegistryPath -Force} New-ItemProperty -Path $RegistryPath -Name "Horizontal" -Value $Horizontal -PropertyType DWORD -Force New-ItemProperty -Path $RegistryPath -Name "Vertical" -Value $Vertical -PropertyType DWORD -Force If ($Horizontal -eq $null) {$Horizontal = [int]((Get-WmiObject -Class Win32_VideoController).CurrentHorizontalResolution)} If ($Vertical -eq $null) {$Vertical = [int]((Get-WmiObject -Class Win32_VideoController).CurrentVerticalResolution)} If ($Horizontal -eq $null) {$Horizontal = [int]"1024"} If ($Vertical -eq $null) {$Vertical = [int]"768"} If ($Horizontal/$Vertical -le 1.4) { $Ratio = "4x3" } Else { $Ratio = "16x9" } $SourceDir = "$LocalSource\$Ratio" If (!(Test-Path($SourceDir))) { Write-Host "$SourceDir does not exist." Exit } # Select a random file as the source wallpaper. $Files = (dir -Path $SourceDir\* -Recurse).FullName $SourceFile = $Files | Get-Random # If username does not start with Student, look to see if the user has a personal wallpaper they wish to use instead. If (!(($env:USERNAME) -like "Student*")) { If (Test-Path("$env:userprofile\Documents\Wallpaper\Wallpaper.jpg")) { $SourceFile = "$env:userprofile\Documents\Wallpaper\Wallpaper.jpg" } ElseIf (Test-Path("$env:homeshare\Wallpaper\Wallpaper.jpg")) { $SourceFile = "$env:homeshare\Wallpaper\Wallpaper.jpg" } } # If no source file exists, exit. If (!(Test-Path($SourceFile))) { Write-Host "$SourceFile does not exist." Exit } If ($? -eq $false) { Write-Host "Null Source File." Exit } # Use .Net Framework to create a class to update and refresh the Wallpaper. Add-Type @” using System; using System.Runtime.InteropServices; using Microsoft.Win32; namespace Wallpaper { public class UpdateImage { [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern int SystemParametersInfo (int uAction, int uParam, string lpvParam, int fuWinIni); public static void Refresh(string path) { SystemParametersInfo( 20, 0, path, 0x01 | 0x02 ); } } } “@ # Enable the creation of images. Add-Type -AssemblyName System.Drawing # Select a font, size and style. $TextSizePixels=$TextSizePoint/0.75 $Font = New-Object System.Drawing.Font("Arial",$TextSizePixels,[Drawing.FontStyle]'Bold',"Pixel") # Get source image from source file. $SourceImage = [system.Drawing.Image]::FromFile($SourceFile) # Create a new bitmap at the primary monitor resolution to construct an image. $Bitmap = New-Object System.Drawing.Bitmap($Horizontal,$Vertical) # Create image for editing. $Image = [system.Drawing.Graphics]::FromImage($Bitmap) # Ensure the image is clear. $Image.Clear([system.Drawing.Color]::FromArgb(255,255,255,255)) # Set the ARGB values required for the text and text box. $TextARGB = [system.Drawing.Color]::FromArgb(255,$TextRed,$TextGreen,$TextBlue) $BoxARGB = [system.Drawing.Color]::FromArgb(255,$BoxRed,$BoxGreen,$BoxBlue) # Set area for text placement. $Rectangle = [system.Drawing.RectangleF]::FromLTRB(0, 0, $Horizontal, $Vertical) # Set alignment format for the font. $FormatFont = [system.Drawing.StringFormat]::GenericDefault $FormatFont.Alignment = [system.Drawing.StringAlignment]::Far $FormatFont.LineAlignment = [system.Drawing.StringAlignment]::Near # Get text path Layout to work out text box co-ordinates. $TextPath = New-Object System.Drawing.Drawing2D.GraphicsPath $TextPath.AddString($TextLabel,$Font.FontFamily,$Font.Style,$Font.Size,$Rectangle,$FormatFont) # Get co-ordinates of beginning and end of text, and add padding for text box. $StartX = $Horizontal $StartY = $Vertical $EndX = 0 $EndY = 0 ForEach ($PathPointRow in $TextPath.PathPoints) { If ($PathPointRow.X -le $StartX){$StartX = $PathPointRow.X} If ($PathPointRow.Y -le $StartY){$StartY = $PathPointRow.Y} If ($PathPointRow.X -gt $EndX){$EndX = $PathPointRow.X} If ($PathPointRow.Y -gt $EndY){$EndY = $PathPointRow.Y} } $EndX = $EndX - $StartX + 5 $EndY = $EndY - $StartY + 10 $StartY = $StartY - 5 $StartX = $StartX # Set up the brush colours for drawing text box and text string. $BoxBrushColour = New-Object Drawing.SolidBrush $BoxARGB $TextBrushColour = New-Object Drawing.SolidBrush $TextARGB # Draw image. $Image.DrawImage($SourceImage,0,0, $Horizontal, $Vertical) # Draw box. $Image.FillRectangle($BoxBrushColour,$StartX,$StartY,$EndX,$EndY) # Draw text. $Image.DrawString($TextLabel,$Font,$TextBrushColour,$Rectangle,$FormatFont) # Save edited bitmap to file. $Bitmap.Save($DestinationFile,[system.Drawing.Imaging.ImageFormat]::Jpeg) # Clean up and remove objects. $SourceImage.Dispose() $Bitmap.Dispose() $Image.Dispose() $SourceDestinationFile # Open saved file. #Invoke-Item $DestinationFile # Update wallpaper. [Wallpaper.UpdateImage]::Refresh($DestinationFile)
     
    Copy and paste the code above into PowerShell ISE, so you can create a PS1 file, and test the code if you so wish.
     
    Please note:

    PowerShell ISE needs to be run as an Administrator for certain aspects of the script to work.
    Edit the section after '$TextLabel ="' to change the text which is saved on the wallpaper.
    Rename SchoolName in the script to the actual School Name (i.e. the folder you just copied to you Domain Controller’s netlogon share).

    Save the script as \\FQDN\netlogon\Logon Info.ps1 (where FQDN is the fully qualified domain name for your active directory domain).
     
    When running the script as an Administrator, you should find this will grab a random file from the correct screen ratio folder (or nearest, if you have a non-standard/old widescreen) generate the text to overlay (so in this case School Address, User Name, Computer Name, Model and Serial Number in the top right) and save the file to the user’s temporary folder %Temp%\LogonInfo.jpg
    On a typical computer this would be: C:\Users\%Username%\AppData\Local\Temp\LogonInfo.jpg[/Code]
     
    This script will also grab the most accurate data of the screens current resolution and store it in the registry location HKEY_LOCAL_MACHINE\Software\MachineData, which can then also be used by the Boot Info script.
     
    Please note that the wallpaper will not change until we update group policy to force this new file, but you can view the output in the folder mentioned above.
     
    [b]Group Policy
     
    [/b]The group policy settings to enforce these wallpapers are as follows.
     
    For the logon wallpaper, this will affect User Policy, so either create a new policy for the users, or edit an existing one and:
     
    [/size]

    [size=1]Go to User Configuration -> Policies -> Windows Settings -> Scripts (Logon/Logoff) -> Logon, and then click on the PowerShell Scripts tab, press Add, and for the script name type in the full path you stored the logon script (i.e. \\FQDN\netlogon\Logon Info.ps1).[/size]
    [size=1]Go to User Configuration -> Policies -> Administrative Templates -> Desktop -> Desktop -> Desktop Wallpaper, and enable the policy, specifying the location as %temp%\LogonInfo.jpg and setting the wallpaper style to Stretch.[/size]

    [size=1]
    For the boot wallpaper, this will affect Computer Policy, so either create a new policy for the machines, or edit an existing one and:
     
    [/size]

    [size=1]Go to User Configuration -> Policies -> Windows Settings -> Scripts (Logon/Logoff) -> Logon, and then click on the PowerShell Scripts tab, press Add, and for the script name type in the full path you stored the Update Wallpapers script (i.e. \\FQDN\netlogon\Update Wallpapers.ps1), next add another script name again, this time type the full path for the boot script (i.e. C:\Program Files\SchoolName\Wallpaper\Boot Info.ps1).[/size]
    [size=1]Go to User Configuration -> Policies -> Administrative Templates -> Control Panel -> Personalization -> Force a specific default lock screen and logon image, and enable the policy, specifying the location as: [Code]C:\Windows\System32\oobe\info\backgrounds\backgroundDefault.jpg[/Code][/size]


  3. DJ-1701
    Please see: https://github.com/DJ-1701/407WorkAround for latest instructions.
     
     
     
     
     
     
     
     
     
     
     
    So, you've followed the instructions for deploying Office 365 Pro Plus with Device Based Activation... most likely from an online instruction, such as this awesome one… but, when you come to running the OPPTransition.exe you get a problem that looks a little like this one...
     

    C:\O365>OPPTransition.exe -Tenant TENANTUUID -Key KEYUUID -Domain contoso.onmicrosoft.com 00:00:00 | OPPTransition started - 1.1.12.95 00:00:00 | Reading arguments 00:00:01 | Args: -tenant TENANTUUID -domain contoso.onmicrosoft.com 00:00:01 | Args Valid 00:00:01 | Nonce: RANDOMTEXTHERE 00:00:01 | Start not logged 00:00:01 | One or more errors occurred. 00:00:01 | System.AggregateException: One or more errors occurred. ---> System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The remote server returned an error: (407) Proxy Authentication Required. at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult) at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar) --- End of inner exception stack trace --- --- End of inner exception stack trace --- at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification) at OPP_Transition.HttpHelperClient.GetResponseWithStatus(String Uri, Status Status) ---> (Inner Exception #0) System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The remote server returned an error: (407) Proxy Authentication Required. at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult) at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar) --- End of inner exception stack trace ---<--- 00:00:02 | PreflightCheck failed - wait: 505
     
    The problem is that you're using an AD user based web filtering system, and the program is unable to transfer information about who is logged on to authenticate to the proxy server... So, how do you get around that?
     
    If you edit the Dot Net machine.config file (i.e. C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config) you can add a section in to place a proxy server that does not use AD based filtering. Before the </configuration> section, enter the following line, changing PROXYDETAILSHERE:PORT with your non AD user based web filtering system and proxy.
    <system.net><defaultProxy enabled="true" useDefaultCredentials="true"><proxy usesystemdefault="true" proxyaddress="PROXYDETAILSHERE:PORT" bypassonlocal="true"/></defaultProxy></system.net>
     
    Although, I find it's easier to do this in a script, and to reset it back afterwards (just in case).
     

    $OriginalData = Get-Content("C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config") $OriginalEnd = '</configuration>' $TempEnd = '<system.net><defaultProxy enabled="true" useDefaultCredentials="true"><proxy usesystemdefault="true" proxyaddress="[b]PROXYDETAILSHERE:PORT[/b]" bypassonlocal="true"/></defaultProxy></system.net></configuration>' $TempData = $OriginalData -replace $OriginalEnd,$TempEnd If ((Get-DAConnectionStatus).Status -ne "ConnectedRemotely") { If (!($OriginalData -like "*proxyaddress=*")) { If ($OriginalData -like "</configuration>") { Set-Content -Path "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config" -Value $TempData } } } .\OPPTransition.exe -Tenant [b]TENANTUUID[/b] -Key [b]KEYUUID[/b] -Domain [b]DOMAIN[/b] Set-Content -Path "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config" -Value $OriginalData
  4. DJ-1701
    http://www.edugeek.net/forums/enterprise-software/205256-sccm-deploying-solus-3-sims-net.html#post1758080
     
     
     
     
     
     
     
     
     
     
    Due to strange issues pushing out the Solus agent from the Solus server, I have decided to take a leaf out of @Boredguy's book and not bother pushing out from the server console... but instead deploy it with a script which records the GUID in a CSV file for easy reinstallation.
     
    Notes:
    The following is setup for a 64 Bit Windows OSes, but can be modified to work with 32 Bit by adding a few lines of code and the installer. If you can not find a copy of the Solus agent on your server, you can go into Solus Deployment Service, click Settings, SOLUS3, SOLUS, Export agent installer.
     
    Let's get started...
     
    In a new folder on your software deployment server share, create a folder called Solus and copy the following items:
    Solus3.Keys.DeploymentService.Public.xml (From the Solus Server)
    SOLUS3AgentInstaller_x64.msi (From the Solus Server)
    Agents.csv (new blank file, needs user write permissions to this file only)
    SolusInstaller.ps1 (i.e. coding below).
     
    Coding note:
    1) Replace \\DEPLOYMENT-SERVER-HERE\SHARE-HERE$ with your Deployment share that holds the Solus folder you created.
    2) Replace SOLUS-SERVER-HERE with your Solus Server Name.
     
    PowerShell code for SolusInstaller.ps1:

    $Found=$false $CSV = "\\DEPLOYMENT-SERVER-HERE\SHARE-HERE$\Solus\Agents.csv" $SolusAgentDataList=IMPORT-CSV $CSV -Header ("ID","Name") $GUID=[system.GUID]::NewGuid().ToString() $ComputerName = (Get-Childitem env:computername).Value ForEach ($SolusAgentDataItem in $SolusAgentDataList) { If ($SolusAgentDataItem.Name -eq $ComputerName) { $Found=$true $GUID=$SolusAgentDataItem.ID } } If (!$Found) { Add-Content $CSV "$GUID,$ComputerName`n" } &msiexec.exe /i `"\\DEPLOYMENT-SERVER-HERE\SHARE-HERE$\Solus\SOLUS3AgentInstaller_x64.msi`" AGENTSERVICEADDRESS=`"net.tcp://localhost:52966`" AGENTID=$GUID DEPLOYMENTSERVERADDRESS=`"net.tcp://SOLUS-SERVER-HERE:52965`" RSAKEYPATH=`"\\DEPLOYMENT-SERVER-HERE\SHARE-HERE$\Solus`" /qn /l*v C:\solus.log Start-Sleep -s 5
     
    To ensure you reuse the same GUID, and get your SIMS/FMS/Discover automatically reinstalled when you rebuild your PC, you can get existing Solus agent GUIDs by looking at AGENTID located in HKEY_LOCAL_MACHINE\SOFTWARE\CCS\SOLUS3\Agent and adding manually to the CSV file in the format.

    01234567-89ab-cdef-0123-456789abcdef,Computer-Name-Here
    with a new line at the end.
     
    When the script is run on any machine with a computer name that hasn't been recorded in the CSV file, as long as you have given the Installer write permissions to the CSV file, a new GUID and the computer name will be added into the CSV file. You can then go on Solus and assigned SIMS/FMS/Discover to the Agent.
     
    When the script is run on any machine with a computer name that IS recorded in the CSV file, the GUID is picked up from the CSV file and Solus will install with the software you had previously specified.
  5. DJ-1701
    One of the schools I look after has SSL Interception in the form of NetASQ (aka StormShield) to protect from particular content. I thought making a list would be helpful to anyone else having problems with certain sites or technology.
     
    This is a list of addresses I had to request to bypass the SSL Interception certificate to function correctly.
     
    https://portal.office.com
    https://outlook.office.com
    https://www.amazon.co.uk
    https://www.sainsburys.co.uk
    https://www.webex.com
    https://serco.webex.com
    https://global-nebulai.webex.com
    https://www.nwolb.com
    https://securenetplus.swgfl.org.uk
    https://evolve.edufocus.co.uk
    https://cdn.musicexpress.co.uk (Note: Amazon Hosting range had to be unblocked as well for this to work.)
    https://www.musicexpress.co.uk (Note: Amazon Hosting range had to be unblocked as well for this to work.)
     
    ap.nvc.enGB.nuancemobility.net via port 443 (Dragon Dictation iOS App deliberately does not use the HTTPS protocol to transmit data on this port, so if any sort of protocol analysis/filtering is taking place, the app fails.)
  6. DJ-1701
    Robocopy is a great command for backing up data between drives or across the network on a scheduled basis.
     
    Generally I create a batch file with commands like the following to mirror data over night when no one (ok, nearly no one) is accessing the content.
     

    E: CD\ robocopy "E:\SharedTeacher$" "\\AAA-MS-XX\Backup$\Teachers$" /MIR /R:1 /W:1 /NP > "E:\Logs\Teachers to MSXX.log" robocopy "E:\SharedAdmin$" "\\AAA-MS-XX\Backup$\Admin$" /MIR /R:1 /W:1 /NP > "E:\Logs\Admin to MSXX.log"
     
    As you can see, I output the results to a file, so I can review. Problem is, the more Robocopy commands that are used, across different servers, the more files I have to check through where most of the time the process would have been successful... Wouldn't it be much simpler if a brief summary was e-mailed to us...
     
    If you have an SMTP relay setup, excellent you're most of the way there already, if not, this is how I set one up on Windows 2012 R2 (and can be done on previous versions back to at least 2003, though instructions may vary).
     
    Install the Server feature 'SMTP Relay' and accept all the dependencies.
     

    Open Internet Information Services (IIS) 6.0 Manager, right click on [sMTP Virtual Server] and select Properties.
     

    Click on the Advanced tab.
     

    Ensure you have a port 25 setup for incoming mail.
    Note: You may need to add a Windows Firewall rule to allow traffic to the server on that port.
     

    On the Access tab, click Authentication.
     

    Tick Anonymous access and OK.
     

    Click the Connection button and list the Server IP Address you wish to send email via this server. Click OK.
     

    Click the Relay button and list the Server IP Address you wish to send email via this server. Click OK.
     

    Make sure you have sensible limits on the Messages tab.
     

    Click the Delivery tab, followed by the Outbound Security button.
     

    Select Basic authentication and type an e-mail address you wish the information to be sent from, as well as the password. Click OK.
     

    In Advanced, type the FQDN of your local server. For smart host, type your smtp address. In this example we are sending out to our Office 365 account, so the smart host is: SMTP.office365.com
     
    Now that you have an SMTP relay up and running, we will want to create a script to scan the robocopy log files and email if there is an issue... here's one I made earlier...
     

    $Computername = (Get-Childitem env:computername).Value $Log = "" $DetectedFailure = 0 # Mail relay settings (The local server configured to send an e-mail). $SMTPSERVER = "ms00.internal.school.county.sch.uk" $MAILFROM = "[email protected]" $MAILTO = "[email protected]" $MESSAGE = "" function funcResultCheck () { $DirError = 9 $FileError = 9 $ByteError = 9 $Data = Get-Content($Log) ForEach ($Line in $Data) { # Dirs - Manual Error Testing Comment # 0 1Total 2Copied 3Skipped 4Mismatch 5FAILED 6Extras #$Line = " Dirs : 1 0 1 0 0 0" If ($Line.Contains("Dirs :")) { $Line = $Line -replace "Dirs :","" $Line = $Line -replace " ",";" Do { $Line = $Line -replace ";;",";" }While ($Line.Contains(";;")) $DirValues = $Line -split ";" $DirError = 9 If ($DirValues.Count -eq 7) { $DirError = [int]$DirValues[5] If (!($?)) {$DirError = 9} } } # Files - Manual Error Testing Comment # 0 1Total 2Copied 3Skipped 4Mismatch 5FAILED 6Extras #$Line = " Files : 1 0 0 0 1 0" If ($Line.Contains("Files :")) { $Line = $Line -replace "Files :","" $Line = $Line -replace " ",";" Do { $Line = $Line -replace ";;",";" }While ($Line.Contains(";;")) $FileValues = $Line -split ";" $FileError = 9 If ($FileValues.Count -eq 7) { $FileError = [int]$FileValues[5] If (!($?)) {$FileError = 9} } } # Bytes - Manual Error Testing Comment # 0 1Total 2Copied 3Skipped 4Mismatch 5FAILED 6Extras #$Line = " Bytes : 15.0 k 0 0 0 15.0 k 0" If ($Line.Contains("Bytes :")) { $Line = $Line -replace "Bytes :","" $Line = $Line -replace "[a-z]","" $Line = $Line.TrimEnd() $Line = $Line -replace " ",";" Do { $Line = $Line -replace ";;",";" }While ($Line.Contains(";;")) $ByteValues = $Line -split ";" $ByteError = 9 If ($ByteValues.Count -eq 7) { $ByteError = [int]$ByteValues[5] If (!($?)) {$ByteError = 9} } } } $TotalError = $DirError + $FileError + $ByteError If ($TotalError -eq 0) { Write-Host "Successful! :D" $MESSAGE = $MESSAGE + $Log + " - Successful !`n" } Else { Write-Host "Unsuccessful! D:" $MESSAGE = $MESSAGE + $Log + " - FAILED! D:!!!`n" $DetectedFailure = 1 } } $Log = "E:\Logs\Teachers to MSXX.log" . funcResultCheck $Log = "E:\Logs\Admin to MSXX.log" . funcResultCheck #Set subject message based on value of text in ResultsEmail if($DetectedFailure -eq 1){$MAILSUBJECT = "$Computername Backup FAILURE"}else {$MAILSUBJECT = "$Computername Backup Success"} $MESSAGE = "This is a backup message from " + $Computername + ".`n`n$Computername Backup has been Processed. Results as follows:`n`n" + $MESSAGE + "`nServer Automated Message" Send-MailMessage -To "$MAILTO" -From "$MAILFROM" -Subject "$MAILSUBJECT" -Body "$MESSAGE" -SmtpServer "$SMTPSERVER"
     
    Remember to replace the value set for:
    - $SMTPSERVER with your FQDN or IP Address of your SMTP relay server.
    - $MAILFROM with the email account you will be sending the message from (same as the one used on the relay server).
    $MAILTO with the e-mail address of who you want the report sent to.
    $Log with the name of the log file you wish to check.
     
    After specifing the log file to check, always make sure there is a new line with

    . funcResultCheck
    This will tell the script to check the file to see if it failed to copy any file.
     
    You can run the script manually to test the result.
     
    When you are happy that everything has been setup, you can go back to your batch file running robocopy and at the end type this line (modifying for path an script name of course).
     

    powershell.exe -noprofile -executionpolicy bypass -file "E:\Tasks\RoboCheck.ps1"
  7. DJ-1701
    This assumes no knowledge of MDT and no prior installation and is one of many ways of configuration.
     
    First of all, download the following:
     
    ADK for Windows 10
    https://msdn.microsoft.com/en-us/windows/hardware/dn913721.aspx#adkwin10
     
    MDT 2013 Update 1
    https://www.microsoft.com/en-us/download/details.aspx?id=48595
     
    Windows 10 Pro/Edu/Ent ISO/DVD
    https://www.microsoft.com/Licensing/servicecenter/default.aspx
     
    ADK
    On the server you have designated for MDT, install ADK for Windows 10 to a directory of your choosing, selecting No to the Participation for the Windows Kits. The main feature you want to install is the Deployment Tools and the Windows Preinstallation Environment (Windows PE), you can if you wish install other elements if you will be experimenting with them later.
     
    MDT - Deployment Share Creation
    Run the installer, select a directory of your choosing to install MDT. For the Customer Experience Improvement Program select 'I don't want to join the program at this time'.
     
    Once MDT has installed, launch Deployment Workbench, right click and select New Deployment Share. When asked for a path, enter a path of X:\DeploymentShare (where X is a drive letter of plenty of space for storing the OS and any future drivers). For this instruction, it will be assumed you will have the Share name of DeploymentShare$.
     

    You will be asked to customise the default behaviour for MDT. The settings I have chosen in this example with the reasons are as follows.
     
    Ask if a computer backup should be performed. - No (As I will only be building or reinstalling PCs).
    Ask for a product key - No (As I use KMS).
    Ask to set the local Administrator password - No (As I will be setting this on the Task Sequence (shown later).
    Ask if an image should be captured - No (As I will be deploying fresh installations of Windows from the media and then updating).
    Ask if BitLocker should be enabled - No (As I can set BitLocker in the Task Sequence if required).
     
    You can then finish the New Deployment Share Wizard.
     
    MDT - Updating the Deployment Share Properties
    Right click on the Deployment Share and select Properties.
     
    If you wish to enable monitoring on the state of the builds, go to the Monitoring tab and select the Enable monitoring tick box.
     
    If you won't be booting any computers off of a CD to connect to the network deployment share, go to the Windows PE tab and deselect the Generate a Lite Touch bootable ISO image. Change the Platform at the top and repeat the settings for the x64 image.
     
    On the Rules tab, create a couple of new lines, then enter any custom settings you wish. The settings I use are below.
     

    SkipLocaleSelection=YES UserLocale=en-GB SystemLocale=en-GB UIlanguage=en-US KeyboardLocale=0809:00000809 TimeZoneName=GMT Standard Time SkipTimeZone=YES SkipAppsOnUpgrade=YES SkipUserData=YES SkipSummary=YES WSUSServer=http://WIN-MS-01:8530 MachineObjectOU=OU=Workstations,DC=Horcrux,DC=Voldemort,DC=JKR,DC=Sch,DC=UK JoinDomain=Horcrux FinishAction=REBOOT
     
    The top box of text sets the local to the UK. The second section of code disables screens such as the USMT as I won't be needing it. The third lot of settings specifies the WSUS server, the default location where I want to add computers and the domain name. Last but not least after a successful install, I want the PC to reboot so users can start using the machine (as I have a GPO with all the settings I want for the PC in the OU we are creating this in).
     
    Click on the Bootstrap.ini button.
     
    Under the [Default] header, enter the following:
     

    KeyboardLocalePE=0809:00000809 SkipBDDWelcome=YES DeployRoot=\\DeploymentServer\DeploymentShare$
     
    This sets the Windows PE keyboard to English UK (so the " and @ keys are mapped to the correct place!). Skips the first page welcoming you to Windows PE and immediately presents you with the username and password field. DeploymentRoot defines the location to pick up the Custom Settings file we updated in the previous section, the task sequences and the Operating Systems. Save the file and click ok.
     
    Note: Whenever you change the Bootstrap.ini, add replace the Windows PE with one from an updated ADK or add new network or storage drivers, you will need to regenerate the WDS wim. This will be discussed later.
     
    MDT - Adding the Operating System
    In the Deployment Share section, right click on Operating Systems and select Import Operating System. Either mount the Windows 10 ISO image (double click in Server 2012) or put the DVD in the drive.
     
    Select 'Full set of source files' and click Next (you could just select the WIM file, but I like to make sure I have all the files, just in case). Select the Drive letter the Windows 10 ISO/DVD is on and click Next.
     
    Give the OS a relevant name or left with the default and click Next. On the Summary window, click Next and once Finished, click Finish.
     
    MDT - Adding a Task Sequence
    In the Deployment Share section, right click on Task Sequences and select New Task Sequence. Enter a Task sequence ID and name, for example ID: 10x64 Name: Windows 10 x64 and click Next. As this Task Sequence will be for building a new PC, select the Template 'Standard Client Task Sequence' and click Next.
     
    Select the OS you wish to deploy and click Next. For the Product Key section, if you are using KMS to activate Windows, just select 'Do not specify a product key at this time' and click Next. For the full name and organisation, type your School/Business name, you can also customise the default Internet Explorer Home Page if you wish and click Next.
     
    Enter a local Administrator account password you want on the machine and click Next. Click Next on the Summary and Finish on the Confirmation.
     
    MDT - Updating the Task Sequence
    Double click on the Task Sequence you have just created.
     

     
    As we want this sequence to always format the machine, we are going to move a few tasks. Expand the Preinstall section, followed by the New Computer only section and move the Validate, Format and Partition Disk (BIOS), Format and Partition Disk (UEFI) and Copy scripts tasks up above the New Computer only section and underneath the Gather local only section.
     
    As part of the build process, I want the machine to connect to our WSUS server to make sure it's up to date. To do this I will expand the State Restore section and click on the Windows Update (Pre-Application Installation) task, click on Options, and untick the 'Disable this step' and make sure 'Continue on error' is ticked. In case I decide to use MDT to deploy any applications in the future, I will also make these changes to the Windows Update (Post-Application Installation) task.
     
    As part of the build process, I want to add Dot Net 3.5, as some of my applications require it. To do this I go to the Custom Tasks section and click 'Add', 'General', 'Run Command Line'. On the Properties tab I change the name of the task to Dot Net 3.5 and for the command line I type:
     

    Dism /online /enable-feature /featurename:NetFX3 /All /Source:"\\DeploymentServer\DeploymentShare$\Operating Systems\Windows 10 Education VL 2015-11 x64\sources\sxs" /LimitAccess
     
    As we have some PowerShell scripts which we like to run, I want to change the PowerShell execution policy. To do this I go to the Custom Tasks section and click 'Add', 'General', 'Run Command Line'. On the Properties tab I change the name of the task to Enable PowerShell Scripts and for the command line I type:
     

    powershell.exe Set-ExecutionPolicy RemoteSigned
     
    Note: If I want to I could also make a custom batch file in a folder on \\DeploymentServer\DeploymentShare$\Scripts and run this from a task sequence. if I want to refer to the scripts folder within a task sequence I can used the variable %SCRIPTROOT% (i.e. %SCRIPTROOT%\Custom\School.cmd).
     
    Creating/Updating the Boot WIMs.
    Right click on the Deployment Share and select Update Deployment Share. Select the option to Completely regenerate the boot images and click Next. Click Next on the Summary. Once the process is complete (it may take some time), click Finish.
     

    Note: If you need to change Bootstrap.ini, add any Network Drivers or Storage Drivers to the drivers folder, you will need to follow the above so the Windows PE environment can access these devices or changes.
     
    WDS - Setup
    On your MDT server, add the Server Role of Windows Deployment Services, and accept the defaults. Once installed, launch Windows Deployment Services, right click on the Server object and click Configure Server. On the options, select Integrated with Active Directory, set the drive letter for the path to the same drive letter used for the MDT Deployment Share (i.e. X:\RemoteInstall instead of C:\RemoteInstall).
     
    On the Proxy DHCP window, if you are running DHCP on the same server tick both boxes, if not untick them and click Next. Select Respond to all client computers (known and unknown) and click Next. Once the Service has installed, click Finish.
     
    WDS - Boot Images
    Under the Server, right click the Boot Images folder and select 'Add Boot Image...'. Select the file X:\DeploymentShare\Boot\LiteTouchPE_x86.wim and click Next, you can change the display name if you wish and click Next, Next and eventually Finish.
     
    Repeat the above for the X:\DeploymentShare\Boot\LiteTouchPE_x64.wim file.
     
    Installing your PC
    To install your PC, enable network boot and start up your machine.
     

    When prompted, press F12.
     

    On some computers you may only see the x86 image or x64 boot wim files. Select one of the two files to continue.
     

    Enter your build account (or admin account), username, password and domain to install and click OK.
     

    Select the Windows version you want to install from fresh on your machine and click Next.
     

    Change the computer name, and if you want the PC in a different OU, amend the OU details.
     

    The PC will now install. If there are any errors you should get a report at the end.
     
    Extras - Security
    Once you are happy with everything, you can add some security features.
     
    Using Part 2 - Steps 2 to 9 (excluding LABEL hardyubuntudesktop32 and below) from this guide, you can password protect before using the getting the Windows Deployment Services menu. This helps prevent users loading a command prompt or other tools in the Windows PE environment unless they know the password.
     
    If you want to disable any interaction during the building process, you can add these two lines in the Custom Settings section.
    DisableTaskMgr=YES
    HideShell=YES
     
    Extras - Multiple OUs
    If you want to have a selection box of OUs to place the computer in, you can find a guide how to do this here: https://scriptimus.wordpress.com/2013/02/11/mdt-2012-domainous-list/
    You will need to remove the line MachineObjectOU=... from your Custom Settings file for this to work.
     
    Troubleshooting
    If after entering your username password and domain in Windows PE, if it just hangs there, check to make sure that the DeploymentShare share permission has been set for the user.
×
×
  • Create New...