Mick's IT Blogs

My blog is here to help solve issues I have encountered and solved, publish scripts I have written, and educate others in understanding areas that are not well covered.

Mick's IT Blogs

Information Technology Zone

14 April 2015

PowerShell: Move PowerShell console during script execution

I heavily use PowerShell during the SCCM imaging process for installing each application. There are often times that I will watch the build to make sure everything is working correctly. When it calls a task sequence which calls a PowerShell script, the script will often open up in the top left of the screen and is covered up by the build status window. This function and the AutoIT script will allow for the console window to be moved while the script is executing. This does require executing the AutoIT script from the powershell script. There have been other methods shown for doing this, but from what I have seen, they are far more cumbersome.


AutoIT Script
 Sleep(500)  
 $WindowName = $CmdLine[1]  
 If WinExists($WindowName) Then  
      $aWinGetPos = WinGetPos($WindowName)  
      $Y = (@DesktopHeight / 2) - ($aWinGetPos[2] / 3)  
      $X = (@DesktopWidth / 2) - ($aWinGetPos[3] / 1)  
      WinMove($WindowName, "", $X, $Y)  
 EndIf  
   


PowerShell Function
 function MoveConsoleWindow {  
      $WindowName = $Host.ui.RawUI.WindowTitle  
      start-process -filepath "\\FileShare\MovePowerShellWindow\CenterPowerShellWindow.exe" -argumentlist $WindowName  
 }  
   

10 April 2015

PowerShell: Application List

This script will generate a list of installed applications minus those in the exclusion list text file. I created this script so the help desk could have a concise list of applications that need to be installed post-build. The script excludes all apps that are in the exclusion list, which includes everything in our build. I wrote the script so that it can be executed from SCCM on a per system basis. It could be modified to allow it to execute on remote machines.

The first thing to do is to create the ExclusionList.txt file and place it in the same directory as the script. Next is create a package in SCCM. That is all that is to it.

You can download the script from here.


 <#  
 .SYNOPSIS  
   Installed Applications  
 .DESCRIPTION  
   This will retrieve the list of installed applications from   
   add/remove programs  
 .Author  
   Mick Pletcher  
 .Date  
   09 April 2015  
 .EXAMPLE  
   powershell.exe -executionpolicy bypass -file InstalledApplications.ps1  
 #>  
   
 #Declare Global Variables  
 Set-Variable -Name Architecture -Scope Global -Force  
 Set-Variable -Name Applications -Scope Global -Force  
 Set-Variable -Name LogFile -Value "c:\Applications.csv" -Scope Global -Force  
 Set-Variable -Name RelativePath -Scope Global -Force  
   
 function Get-RelativePath {  
      $Global:RelativePath = (split-path $SCRIPT:MyInvocation.MyCommand.Path -parent)+"\"  
 }  
   
 function Get-Architecture {  
      $Global:Architecture = Get-WmiObject -Class Win32_OperatingSystem | Select-Object OSArchitecture  
      $Global:Architecture = $Global:Architecture.OSArchitecture  
      #Returns 32-bit or 64-bit  
 }  
   
 function CreateLogFile {  
      #Define Local Variables  
      Set-Variable -Name Output -Scope Local -Force  
      Set-Variable -Name Temp -Scope Local -Force  
        
      if ((Test-Path $Global:LogFile) -eq $true) {  
           Remove-Item -Path $Global:LogFile -Force  
      }  
      if ((Test-Path $Global:LogFile) -eq $false) {  
           $Temp = New-Item -Path $Global:LogFile -ItemType file -Force  
      }  
      $Output = "Application Name"  
      Out-File -FilePath $Global:LogFile -InputObject $Output -Append -Force -Encoding UTF8  
                       
        
      #Cleanup Local Variables  
      Remove-Variable -Name Output -Scope Local -Force  
      Remove-Variable -Name Temp -Scope Local -Force  
 }  
   
 function GetAddRemovePrograms {  
      #Define Local Variables  
      Set-Variable -Name Applicationsx86 -Scope Local -Force  
      Set-Variable -Name Applicationsx64 -Scope Local -Force  
      Set-Variable -Name ARPx86 -Scope Local -Force  
      Set-Variable -Name ARPx64 -Scope Local -Force  
        
      $ARPx86 = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"  
      $ARPx64 = "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\"  
      if ($Global:Architecture -eq "32-bit") {  
           $Applicationsx86 = Get-ChildItem -Path $ARPx86 | ForEach-Object -Process {$_.GetValue("DisplayName")}  
      } else {  
           $Applicationsx86 = Get-ChildItem -Path $ARPx64 | ForEach-Object -Process {$_.GetValue("DisplayName")}  
           $Applicationsx64 = Get-ChildItem -Path $ARPx86 | ForEach-Object -Process {$_.GetValue("DisplayName")}  
      }  
      $Global:Applications = $Applicationsx86 + $Applicationsx64  
      $Global:Applications = $Global:Applications | Sort-Object  
      $Global:Applications = $Global:Applications | select -Unique  
        
      #Cleanup Local Memory  
      Remove-Variable -Name Applicationsx86 -Force  
      Remove-Variable -Name Applicationsx64 -Force  
      Remove-Variable -Name ARPx86 -Force  
      Remove-Variable -Name ARPx64 -Force  
 }  
   
 function GenerateReport {  
      #Define Local Variables  
      Set-Variable -Name Application -Scope Local -Force  
      Set-Variable -Name Exclusions -Scope Local -Force  
      Set-Variable -Name LogFile -Scope Local -Force  
      Set-Variable -Name Print -Value $true -Scope Local -Force  
        
      $Exclusions = Get-Content -Path $RelativePath"ExclusionList.txt"  
      foreach ($Application in $Global:Applications) {  
           if ($Application -ne $null) {  
                $Application = $Application.Trim()  
           }  
           if (($Application -ne "") -and ($Application -ne $null)) {  
                foreach ($Exclusion in $Exclusions) {  
                     $Exclusion = $Exclusion.Trim()  
                     if ($Application -like $Exclusion) {  
                          $Print = $false  
                     }  
                }  
                if ($Print -eq $true) {  
                     Write-Host $Application  
                     Out-File -FilePath $Global:LogFile -InputObject $Application -Append -Force -Encoding UTF8  
                }  
           }  
           $Print = $true  
      }  
   
      #Cleanup Local Variables  
      Remove-Variable -Name Application -Scope Local -Force  
      Remove-Variable -Name Exclusions -Scope Local -Force  
      Remove-Variable -Name LogFile -Scope Local -Force  
      Remove-Variable -Name Print -Scope Local -Force  
 }  
   
 cls  
 Get-RelativePath  
 Get-Architecture  
 CreateLogFile  
 GetAddRemovePrograms  
 GenerateReport  
   
 #Cleanup Global Variables  
 Remove-Variable -Name Architecture -Force  
 Remove-Variable -Name Applications -Force  
 Remove-Variable -Name LogFile -Force  
 Remove-Variable -Name RelativePath -Force  
   

08 April 2015

SCCM: SCCM PowerShell SCUP Alternative

I have wanted to be able to update an application on the fly without having to create new application packages in SCCM. This is especially useful for applications that are updated quite frequently, such as Java Runtime Environment. This can be done by using the custom script detection method. The following script I wrote will go out and extract the product code from the MSI installer located in the source installation directory. It then looks at the HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{GUID} to make sure the application is installed. If that registry key is missing, SCCM will begin installation of the new software.

To make this work correctly, you will need to use the Uninstall-MSIbyName function included in my Deployment Module and listed below. Some installers uninstall the old version, but for best results, I always make sure I perform the uninstall before the install takes place. This will allow for the install script to uninstall the old version and then the installer can come back and install the new version. This function allows for you to input just a portion of the application name listed in Add/Remove programs. An example is Java. In my Java installer, I use the line below which uninstalls all Java version 8 packages:

Uninstall-MSIByName -ApplicationName "Java 8" -Switches "/qb- /norestart"

Next, you will need to rename the MSI installer to a generic name. I called mine JREx86.msi and JREx64.msi. When a new version comes out, I delete these and rename the new version to the same name. The powershell installation package will always look for the same named installer. Once you replace the MSI files, all that is required is to go into the SCCM console, select the deployment, and click Update Content. Once the content is updated on the distribution points and systems begin running the Application Deployment Evaluation Cycle, the package will begin installing the new version of the software.

This script only covers installations involving MSI files. I am also going to write a detection method to cover EXE files too. 

 Function Uninstall-MSIByName {  
      <#  
      .SYNOPSIS  
           Uninstall-MSIByName  
      .DESCRIPTION  
           Uninstalls an MSI application using the MSI file  
      .EXAMPLE  
           Uninstall-MSIByName -ApplicationName "Adobe Reader" -Switches "/qb- /norestart"  
      #>  
   
      Param([String]$ApplicationName, [String]$Switches)  
      $Uninstall = Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall -Recurse -ea SilentlyContinue  
      $Uninstall += Get-ChildItem HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall -Recurse -ea SilentlyContinue  
      $SearchName = "*"+$ApplicationName+"*"  
      $Executable = $Env:windir+"\system32\msiexec.exe"  
      Foreach ($Key in $Uninstall) {  
           $TempKey = $Key.Name -split "\\"  
           If ($TempKey[002] -eq "Microsoft") {  
                $Key = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"+$Key.PSChildName  
           } else {  
                $Key = "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\"+$Key.PSChildName  
           }  
           If ((Test-Path $Key) -eq $true) {  
                $KeyName = Get-ItemProperty -Path $Key  
                If ($KeyName.DisplayName -like $SearchName) {  
                     $TempKey = $KeyName.UninstallString -split " "  
                     If ($TempKey[0] -eq "MsiExec.exe") {  
                          $Output = "Uninstall "+$KeyName.DisplayName+"....."  
                          Write-Host "Uninstall"$KeyName.DisplayName"....." -NoNewline  
                          $Parameters = "/x "+$KeyName.PSChildName+[char]32+$Switches  
                          $ErrCode = (Start-Process -FilePath $Executable -ArgumentList $Parameters -Wait -Passthru).ExitCode  
                          If (($ErrCode -eq 0) -or ($ErrCode -eq 3010) -or ($ErrCode -eq 1605)) {  
                               $Output = $Output+"Success"  
                               Write-Host "Success" -ForegroundColor Yellow  
                          } else {  
                               $Output = $Output+"Failed with error code "+$ErrCode  
                               Write-Host "Failed with error code "$ErrCode -ForegroundColor Red  
                               $Global:Errors++  
                          }  
                          Out-File -FilePath $Global:LogFile -InputObject $Output -Append -Force  
                     }  
                }  
           }  
      }  
 }  
   


 <#  
 .SYNOPSIS  
   SCCM Application Detection for Java Runtime Environment  
 .DESCRIPTION  
   This script will detect if the latest version of Java is installed by performing a query  
   on the MSI for the product key. It then searches the uninstall registry keys for a matching  
   GUID. If it does match, then the script returns a 0 back to SCCM. If it does not match,  
   then the script does not return any code back to SCCM.  
 .Author  
   Mick Pletcher  
 .Date  
   07 April 2015  
 #>  
   
 $Architecture = Get-WmiObject -Class Win32_OperatingSystem | Select-Object OSArchitecture  
 $Architecture = $Architecture.OSArchitecture  
 If ($Architecture -eq "32-bit") {  
      [string]$MSIPath = "\\FileShare\Oracle\JavaTest\JREx86.msi"  
 } else {  
      [string]$MSIPath = "\\FileShare\Oracle\JavaTest\JREx64.msi"  
 }  
 #"ProductCode","ProductVersion","ProductName"  
 [string]$Property = "ProductCode"  
 $WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer  
 $MSIDatabase = $WindowsInstaller.GetType().InvokeMember("OpenDatabase","InvokeMethod",$Null,$WindowsInstaller,@($MSIPath,0))  
 $Query = "SELECT Value FROM Property WHERE Property = '$($Property)'"  
 $View = $MSIDatabase.GetType().InvokeMember("OpenView","InvokeMethod",$null,$MSIDatabase,($Query))  
 $View.GetType().InvokeMember("Execute", "InvokeMethod", $null, $View, $null)  
 $Record = $View.GetType().InvokeMember("Fetch","InvokeMethod",$null,$View,$null)  
 $Value = $Record.GetType().InvokeMember("StringData","GetProperty",$null,$Record,1)  
 If ($Architecture -eq "32-bit") {  
      $RegPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"+$Value  
 } else {  
      $RegPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"+$Value  
 }  
 If ((Test-Path $RegPath) -eq $true) {  
      Return 0  
 } else {}  
   

06 April 2015

Powershell: Get Default Printer

This script will find the default printer of a logged on user and write it to a text file named DefaultPrinter.txt in the %APPDATA% folder. I have this script run as a package in SCCM on a reoccurring weekly basis. This keeps the file up to date in the event a user needs a new machine or a new profile.

You can download the file from here: GetDefaultPrinter.ps1



 <#  
 .SYNOPSIS  
   Get Default Printer  
 .DESCRIPTION  
   Gets the default printer and writes the printer to a text file in the %APPDATA% folder. If  
   this is executed through SCCM, it must be run as the user.  
 .Author  
   Mick Pletcher  
 .Date  
   06 April 2015  
 .EXAMPLE  
   powershell.exe -executionpolicy bypass -file GetDefaultPrinter.ps1  
 #>  
   
 #Declare Global Variables  
 Set-Variable -Name DefaultPrinter -Scope Global -Force  
   
 cls  
 If ((Test-Path $env:APPDATA"\DefaultPrinter.txt") -eq $true) {  
      Remove-Item -Path $env:APPDATA"\DefaultPrinter.txt" -Force  
 }  
 $DefaultPrinter = Get-WmiObject -Class win32_printer -ComputerName "localhost" -Filter "Default='true'" | Select-Object ShareName  
 Write-Host "Default Printer: " -NoNewline  
 If ($DefaultPrinter.ShareName -ne $null) {  
      $DefaultPrinter.ShareName | Out-File -FilePath $env:APPDATA"\DefaultPrinter.txt" -Force -Encoding "ASCII"  
      Write-Host $DefaultPrinter.ShareName  
 } else {  
      $DefaultPrinter = "No Default Printer"  
      $DefaultPrinter | Out-File -FilePath $env:APPDATA"\DefaultPrinter.txt" -Force -Encoding "ASCII"  
      Write-Host $DefaultPrinter  
 }  
   
 #Cleanup Global Variables  
 Remove-Variable -Name DefaultPrinter -Scope Global -Force  
   

27 March 2015

PowerShell: OS Detection

Recently, we added the Windows 8.1 operating system to the company domain. I ran into the problem of deploying Adobe Flash Player to these systems because the ActiveX does not get installed. The issue came up in SCCM where I needed a detection method for the OS using file, registry, or product ID. I needed a way to detect the plugin and windows 8.1 to be able to validate a successful deployment. This gave me the idea to write a powershell script to place a file in the windows directory that is named for the operating system that is running. It makes for easy OS detection in SCCM for future deployments.



 <#  
 .SYNOPSIS  
   Operating System  
 .DESCRIPTION  
   This script will detect what operating system is installed  
   and write a file named for that OS to the windows directory.  
 .EXAMPLE  
   powershell.exe -executionpolicy bypass -file OperatingSytem.ps1  
 #>  
   
 cls  
 $OS = Get-WmiObject -Class Win32_OperatingSystem -ComputerName .  
 Switch ($OS.Version) {  
      5.0.2195 {New-Item -Name "Windows 2000" -Path $env:windir -ItemType File}  
      5.1.2600 {New-Item -Name "Windows XP" -Path $env:windir -ItemType File}  
      5.2.3790 {New-Item -Name "Windows XP 64-Bit" -Path $env:windir -ItemType File}  
      6.0.6000 {New-Item -Name "Windows Vista" -Path $env:windir -ItemType File}  
      6.0.6001 {New-Item -Name "Windows Vista SP1" -Path $env:windir -ItemType File}  
      6.0.6002 {New-Item -Name "Windows Vista SP2" -Path $env:windir -ItemType File}  
      6.1.7600 {New-Item -Name "Windows 7" -Path $env:windir -ItemType File}  
      6.1.7601 {New-Item -Name "Windows 7 SP1" -Path $env:windir -ItemType File}  
      6.2.9200 {New-Item -Name "Windows 8" -Path $env:windir -ItemType File}  
      6.3.9600 {New-Item -Name "Windows 8.1" -Path $env:windir -ItemType File}  
 }  
   

27 February 2015

PowerShell: Cleaning up old systems in Active Directory, SCCM, and Antivirus

Every place I have worked, there has been the issue of systems being in SCCM, AD, and antivirus that no longer existed. The is often caused by systems being overlooked when a user departs the company, a laptop that gets put in a desk and not turned on forever, and a lot of other similar scenarios.

While I was in the process of upgrading SCCM 2007 to 2012, I finally became fed up over it and wrote this script. The script uses All Systems from SCCM as the master list. Here is why. The way I have the SCCM configured is that All Systems is populated by AD. Logically, that means that even if a system has been deleted in AD, it might still be present in SCCM. We use a third party antivirus, so I integrated it by importing a list of all systems it showed with the antivirus client.

The script will first read a system from the SCCM list named SCCMSystems.txt. It reads the antivirus systems from a text file called AntivirusSystems.txt. The text files should be in UTF-8 format. It then runs through three tests. The first test is to query AD. The second test is to check if the system name is included in the antivirus list. The third test is to run a network connectivity test. If the network connectivity test fails, it runs a secondary ping test and reads the output of ping.exe to see if it returns host not found. The Network Connectivity test fails only if a host not found is returned. It passes for any other message because it could be a laptop that is offline at the time.

There is a csv file that is written to for all failures. The csv file contains two primary columns, deletions and additions. Under the deletions, it has AD, antivirus, and SCCM. Under the additions if antivirus. An X is placed in each box indicating the recommended action.

If you do not want/need the antivirus, you can delete that portion out of the script. This script is only a primer for instituting in your organization. It will need to be adapted to your network.

You can download the script from here.




 <#  
 .SYNOPSIS  
   ValidateSystems  
 .DESCRIPTION  
   Validate if a system still exists  
 .Author  
   Mick Pletcher  
 .Date  
   26 February 2015  
 .EXAMPLE  
   powershell.exe -executionpolicy bypass -file ValidateSystems.ps1  
 #>  
   
 Function InitializeGlobalMemory {  
      Set-Variable -Name Computers -Scope Global -Force  
      Set-Variable -Name Logfile -Scope Global -Force  
      Set-Variable -Name RelativePath -Scope Global -Force  
      Set-Variable -Name Webroot -Scope Global -Force  
      $Global:Failures = @()  
      $Global:RelativePath = (split-path $SCRIPT:MyInvocation.MyCommand.Path -parent)+"\"   
      $Global:LogFile = $Global:RelativePath + "Output.csv"  
      $Global:Computers = Get-Content -Path $Global:RelativePath"SCCMSystems.txt" -Force  
      $Global:Webroot = Get-Content -Path $Global:RelativePath"AntivirusSystems.txt" -Force  
   
 }  
   
 Function ProcessLogFile {  
      If ((Test-Path $Global:LogFile) -eq $true) {  
           Remove-Item $Global:LogFile -Force  
      }  
      If ((Test-Path $Global:LogFile) -eq $false) {  
           $temp = New-Item $Global:LogFile -ItemType File -Force  
           $Output = ","+"Deletions"+","+","+","+"Additions"  
           Out-File -FilePath $Global:LogFile -InputObject $Output -Append -Force -Encoding UTF8  
           $Output = "Computer Name"+","+"Active Directory"+","+"SCCM"+","+"Antivirus"+","+"Antivirus"  
           Out-File -FilePath $Global:LogFile -InputObject $Output -Append -Force -Encoding UTF8  
      }  
 }  
   
 Function ProcessComputers {  
      $obj = New-Object PSObject  
      $Count = 0  
      Foreach ($Computer in $Global:Computers) {  
           cls  
           $Antivirus = $false  
           $Count += 1  
           Write-Host "Processing "$Count" of " -NoNewline  
           Write-Host $Global:Computers.Count  
           Write-Host  
           Write-Host "Computer Name: "$Computer  
           $ADAccount = $null  
           #Active Directory  
           Write-Host "Testing AD Presence....." -NoNewline  
           $ErrorActionPreference = 'SilentlyContinue'  
           $ADAccount = Get-ADComputer $Computer  
           If ($ADAccount -eq $null) {  
                $ADAccount = $false  
                Write-Host "Does not Exist" -ForegroundColor Red  
           } else {  
                $ADAccount = $true  
                Write-Host "Exists" -ForegroundColor Yellow  
           }  
           #Antivirus  
           Write-Host "Testing Antivirus....." -NoNewline  
           Foreach ($system in $Global:Webroot) {  
                If ($system -eq $Computer) {  
                     $Antivirus = $true  
                }  
           }  
           If ($Antivirus -eq $true) {  
                Write-Host "Exists" -ForegroundColor Yellow  
           } else {  
                Write-Host "Does not exist" -ForegroundColor Red  
           }  
           #Network Connectivity  
           Write-Host "Testing Network Connectivity....." -NoNewline  
           If ((Test-Connection -ComputerName $Computer -Quiet) -eq $false) {  
                $NetworkTest = ping $Computer  
                If ($NetworkTest -like '*Ping request could not find host*') {  
                     $NetworkTest = $false  
                     Write-Host "Does not exist" -ForegroundColor Red  
                } else {  
                     $NetworkTest = $true  
                     Write-Host "Exists" -ForegroundColor Yellow  
                }  
           } else {  
                $NetworkTest = $true  
                Write-Host "Exists" -ForegroundColor Yellow  
           }  
           If (($ADAccount -eq $true) -and ($NetworkTest -eq $false)) {  
                #Write-Host $Computer -NoNewline  
                #Write-Host " - Delete from AD and SCCM" -BackgroundColor Yellow -ForegroundColor Black  
                $obj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer  
                If ($Antivirus -eq $true) {  
                     $obj | Add-Member -MemberType NoteProperty -Name Action -Value "AD_SCCM_Antivirus"  
                } else {  
                     $obj | Add-Member -MemberType NoteProperty -Name Action -Value "AD_SCCM"  
                }  
           }  
           If (($ADAccount -eq $false) -and ($NetworkTest -eq $false)) {  
                #Write-Host $Computer -NoNewline  
                #Write-Host " - Delete from SCCM" -BackgroundColor Green -ForegroundColor Black  
                $obj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer  
                If ($Antivirus -eq $true) {  
                     $obj | Add-Member -MemberType NoteProperty -Name Action -Value "SCCM_Antivirus"  
                } else {  
                     $obj | Add-Member -MemberType NoteProperty -Name Action -Value "SCCM"  
                }  
           }  
           If (($ADAccount -eq $true) -and ($NetworkTest -eq $true) -and ($Antivirus -eq $false)) {  
                $obj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer  
                $obj | Add-Member -MemberType NoteProperty -Name Action -Value "AddAntivirus"  
           }  
           If ($obj -ne $null) {  
                $Global:Failures += $obj  
                $Output = $obj.ComputerName  
                If ($obj.Action -eq "AD_SCCM") {  
                     $Output = $Output + ","+"X"+","+"X"   
                }  
                If ($obj.Action -eq "AD_SCCM_Antivirus") {  
                     $Output = $Output + ","+"X"+","+"X"+","+"X"  
                }  
                If ($obj.Action -eq "SCCM") {  
                     $Output = $Output + ","+","+"X"  
                }  
                If ($obj.Action -eq "SCCM_Antivirus") {  
                     $Output = $Output + ","+","+"X"+","+"X"  
                }  
                If ($obj.Action -eq "AddAntivirus") {  
                     $Output = $Output + ","+","+","+","+"X"  
                }  
                Out-File -FilePath $Global:LogFile -InputObject $Output -Append -Force -Encoding UTF8  
                Remove-Variable -Name obj  
                $obj = New-Object PSObject  
           }  
           Start-Sleep -Seconds 1  
      }  
 }  
   
 Function WriteToScreen {  
      cls  
      Foreach ($Failure in $Global:Failures) {  
           If ($Failure -ne $null) {  
                Write-Output $Failure  
           }  
      }  
      $ErrorActionPreference = 'Continue'  
 }  
   
 cls  
 Import-Module -Name ActiveDirectory  
 InitializeGlobalMemory  
 ProcessLogFile  
 ProcessComputers  
 WriteToScreen  
   

23 February 2015

PowerShell: Import and Local GPOs

This script will import and apply a local GPO using the local GPO utility, ImportRegPol.exe, located here. The script is a wrapper that makes implementing this utility a snap. All that has to be done is to use the Microsoft Security Compliance Manager to export the desired local GPO. I wrote this script for use mainly in the MDT build. I realize there is the GPO Pack built into MDT, but what happens when you want to deploy a local GPO to machines already built or multiple local GPOs at different times in a build? This script makes that easy.

The syntax for the function is as follows:

Syntax:
Import-LGPO -LGOPName "User Friendly Name" -LGPOLocation "<Path_To_GPO_GUID>" -GPOType "Machine"

Example:
Import-LGPO -LGOPName "Disable Network Wait" -LGPOLocation "\\Fileshare\LGPO\{57D203F7-B8CE-47BC-920F-CECF34F6A6BA}" -GPOType "Machine"

You can download the script from here.



 <#  
 .SYNOPSIS  
   Apply Local Group Policy  
 .Author  
   Mick Pletcher  
 .Date  
   23 February 2015  
 .EXAMPLE  
   powershell.exe -executionpolicy bypass -file LGPO.ps1  
 #>  
   
   
 Function Import-LGPO {  
   
      Param([String]$LGPOName, [String]$LGPOLocation, [String]$GPOType)  
        
      $Executable = $Global:RelativePath+"ImportRegPol.exe"  
      If ($GPOType -eq "Machine") {  
           $GPOType = "\DomainSysvol\GPO\Machine\registry.pol"  
      } else {  
           $GPOType = "\DomainSysvol\GPO\User\registry.pol"  
      }  
      $Parameters = "-m "+[char]34+$LGPOLocation+$GPOType+[char]34  
      Write-Host "Apply Local"$LGPOName" Policy....." -NoNewline  
      $ErrCode = (Start-Process -FilePath $Executable -ArgumentList $Parameters -Wait -Passthru).ExitCode  
      If (($ErrCode -eq 0) -or ($ErrCode -eq 3010)) {  
           Write-Host "Success" -ForegroundColor Yellow  
      } else {  
           Write-Host "Failed with error code "$ErrCode -ForegroundColor Red  
      }  
   
 }  
   
 cls  
 $Global:RelativePath = (split-path $SCRIPT:MyInvocation.MyCommand.Path -parent)+"\"  
 Import-LGPO -LGPOName "User Friendly Name" -LGPOLocation "<Path_To_GPO_GUID>" -GPOType "Machine"  
 Start-Sleep -Seconds 5