My MDT PowerShell Template

By | March 17, 2014
Share

I’ve recently come to really appreciate PowerShell as the most versatile and powerful language available natively in any/all Windows OS.

i.e. 2 lines of code to ensure laptop battery is plugged in and prompt the user.
If ((Get-WmiObject -Query “SELECT * From Win32_Battery”).BatteryStatus -ne 2)
{ Write-Host “Please plug in your laptop” }

An equivalent VBScript would easily run around 30 lines of code.

Running PowerShell via the Task Sequence has been around for a bit, which is simple enough.

This however, does NOT include any logging support and requires that your scripts exist in the “Scripts” Directory. Which in my opinion almost renders the feature useless.

Here is my Template, which can be used within an application:

GitHub Link: https://github.com/brianfgonzalez/Scripts/blob/master/Z-MyMDTTemplate.ps1

<#
Purpose: Replaces Windows 8/8.1 Start Screen Background image.
Version: 1.0 - March 14, 2013

Author - Brian Gonzalez
    Blog   : https://supportishere.com

ChangeLog:
    2014-03-17 BFG:
        - Updated LogHelper output strings to match MDT logging strings.
        - set LogHelper to also write to BDD.log.
#>

# Create Global Variables
$oInvocation = (Get-Variable MyInvocation).Value
$sScriptDirectory = Split-Path $oInvocation.MyCommand.Path
$sScriptNameExt = $oInvocation.MyCommand.Name
$sScriptName = $sScriptNameExt.Substring(0, $sScriptNameExt.Length - 4)

# Ensure script can attach to TS Environment
try
{
    $ErrorActionPreference = "Stop"
    $oTSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment 
    $sLogPath = $oTSEnv.Value("LogPath")

}
catch [System.Runtime.InteropServices.COMException]
{
    $sLogPath = "C:\Windows\Temp\DeploymentLogs" #Hardcode Logs Directory    
}
finally
{$ErrorActionPreference = "Continue"}

# Set Logging File Variables
$sLogFilePath = "$sLogPath\$sScriptName.log"
$sCmdLogFilePath = "$sLogPath\$sScriptName-Cmd.log"
$sBDDLogFilePath = "$sLogPath\BDD.log"
$sTZbias = (Get-WmiObject -Query “Select Bias from Win32_TimeZone”).Bias
$sTime = ((Get-Date -Format hh:mm:ss.fff) + $sTZbias) 
$sDate = Get-Date -Format MM-dd-yyyy

# Function to run processes and capture output
function RunWithLogging
{
    param([string]$cmd,
    [string]$params)
    $ps = new-object System.Diagnostics.Process
    $ps.StartInfo.Filename = $cmd
    $ps.StartInfo.Arguments = $params
    $ps.StartInfo.RedirectStandardOutput = $True
    $ps.StartInfo.UseShellExecute = $false
    $ps.start() | Out-Null
    $ps.WaitForExit()
    [string] $out = $ps.StandardOutput.ReadToEnd();
    $out | Out-File $sCmdLogFilePath -Append
    return $ps.ExitCode
}

function CopyFileWithLogging
{
    param([string]$sSrcFile,
       [string]$sDesFile)
    If (!(Test-Path $sSrcFile))
    {LogHelper "$sSrcFile not found." "Error"}

    try
    {
        $ErrorActionPreference = "stop"
        Copy-Item $sSrcFile $sDesFile -Force -Recurse
    }
    catch [System.Management.Automation.ItemNotFoundException]
    {
        LogHelper ("Could not find target location:  " + $sDesFile) "Error"
        return 1
    }
    catch [System.UnauthorizedAccessException]
    {
        LogHelper ("Access Error: Could not overwrite target file:  " + $sDesFile) "Error"
        return 2
    }
    finally {$ErrorActionPreference = "continue"}

    If (Test-Path $sDesFile)
    {
        LogHelper ($sDesFile + " was copied successfully.")
        return 0
    }
}

function LogHelper
{
    param([string] $sLogContent,
    [string] $sLogType = "Update")

    try
    {
        $ErrorActionPreference = "stop"
        If (!(Test-Path $sLogFilePath))
        {
            # Create Log File
            $sUpdateStringTest = ("<![LOG[Initial LOG Entry]LOG]!><time=""" + $sTime + """ date=""" + `
                $sDate + """ component=""" + $sScriptName + """ context="""" type=""1"" thread="""" file=""" + `
                $sScriptName + """>")
        }
    }
    catch [System.IO.DirectoryNotFoundException]
    {
        Write-Host (Split-Path $sLogFilePath),"folder does not exist"
        New-Item -ItemType Directory (Split-Path $sLogFilePath) | Out-Null
        $sUpdateStringTest = ("<![LOG[Created Logging Directory.]LOG]!><time=""" + $sTime + """ date=""" + `
            $sDate + """ component=""" + $sScriptName + """ context="""" type=""1"" thread="""" file=""" + `
            $sScriptName + """>")
        $sUpdateStringTest | Out-File $sLogFilePath -Append -NoClobber -Encoding Default
    }
    finally {$ErrorActionPreference = "continue"}

    If ($sLogType -eq "Update")
    {
        # Write to log named after script file.
        $sUpdateStringTest = ("<![LOG[" + $sLogContent + "]LOG]!><time=""" + $sTime + """ date=""" + `
            $sDate + """ component=""" + $sScriptName + """ context="""" type=""1"" thread="""" file=""" + `
            $sScriptName + """>")
        $sUpdateStringTest | Out-File $sLogFilePath -Append -NoClobber -Encoding Default
        # Write also to BDD.log
        If (Test-Path $sBDDLogFilePath)
        {$sUpdateStringTest | Out-File $sBDDLogFilePath -Append -NoClobber -Encoding Default}
    }
    ElseIf (($sLogType -eq "Error") -or ($sLogType -eq "Failure"))
    {
        # Write to log named after script file.
        <![LOG[FAILURE (Err):
        $sUpdateStringTest = ("<![LOG[FAILURE (Err):" + $sLogContent + "]LOG]!><time=""" + $sTime + """ date=""" + `
            $sDate + """ component=""" + $sScriptName + """ context="""" type=""1"" thread="""" file=""" + `
            $sScriptName + """>")
        $sUpdateStringTest | Out-File $sLogFilePath -Append -NoClobber -Encoding Default
        # Write also to BDD.log
        If (Test-Path $sBDDLogFilePath)
        {$sUpdateStringTest | Out-File $sBDDLogFilePath -Append -NoClobber -Encoding Default}
    }
}

# Start Main Code Here

# Examples
# Run a Command Line
#LogHelper "About to run a command."
#$sCmd = "$env:SystemDrive\Windows\System32\cmd.exe"
#$sParams = "/C IPCONFIG /ALL"
#$sReturn = RunWithLogging $sCmd $sParams
#LogHelper "Command Completed and Returned: $sReturn"

# Copy a File/Folder
#$sSourceFilePath = ($sScriptDirectory + "\SourceFile.txt")
#$sDestinationFilePath = "C:\Temp"
#LogHelper ("About to copy """ + $sSourceFilePath + """ to " + $sDestinationFilePath)
#$sReturn = CopyFileWithLogging $sSourceFilePath $sDestinationFilePath
#LogHelper ("Copy is complete and returned: $sReturn")

 

/BG

4 thoughts on “My MDT PowerShell Template

  1. David Bloom

    Hi Brian,

    I like this script, but I am having some issues trying to test it out. Admitiddly, I am testing this outside of an MDT task sequence, so the script cannot attach to the TS Environment.

    I am using this script to install an application, and it does that just fine. However, I get errors when trying to write to the log files, because they don’t exist. I can’t see anywhere in the script where it creates these log files if they don’t exist. All I see are commands to update log files, not create them.

    Am I missing something? Thank you!

    Reply
    1. Brian Gonzalez Post author

      David,

      Im happy you found the post. I actually ended up creating a separate script to act like the ZTIUtility.wsf script, but via Powershell.

      Here is the script, must be placed in the Scripts\ Directory.
      https://github.com/brianfgonzalez/Scripts/blob/master/ZTIUtility.ps1

      And here is an example Powershell script using the functions in the other script.
      https://github.com/brianfgonzalez/Scripts/blob/master/ZTIUtility.ps1

      it seems to work great in my testing.

      /BrianG

      Reply
  2. David Bloom

    Hi Brian,

    I keep finding myself back at this page as I need to write my own PowerShell scripts for MDT. I noticed in your reply above that the example you linked to is the same URL as the ZTIUtility.ps1 link.

    Could you please post to a working example that uses the ZTIUtility script? That would be most helpful, at least to me. 🙂

    Thanks.

    Reply

Leave a Reply to Brian Gonzalez Cancel reply

Your email address will not be published.

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.