PowerShell Script – Get Group Policy events by CorrelationID

During his Group Policy: Notes from the Field – Tips, Tricks, and Troubleshooting session at TechEd Group Policy MVP Jeremy Moskowitz demonstrates how to filter the event log using the correlation ID. Now because I love using PowerShell I thought I create a function for that using Jeremy’s XMLquery.

function Get-GPEventByCorrelationID
{
<#
.Synopsis
   Get Group Policy Eventlog entries by Correlation ID
.DESCRIPTION
   This function retrieves Group Policy event log entries filtered by Correlation ID
.EXAMPLE
   Get-GPEventByCorrelationID -CorrelationID A2A621EC-44B4-4C56-9BA3-169B88032EFD

   TimeCreated                     Id LevelDisplayName Message
   -----------                     -- ---------------- -------
   7/17/2014 3:00:27 PM          5117 Information      Group policy session completed successfully.

#>
    [CmdletBinding()]
    Param
    (
        # CorrelationID
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [string]$CorrelationID 
    )

    Begin
    {
        $Query = ''
        $FilterXML = $Query.Replace("CorrelationID",$CorrelationID)
    }
    Process
    {
        Get-WinEvent -FilterXml $FilterXML
    }
    End
    {
    }
}

Greetings form the sunny beaches at Sardinia.

ConfigMgr – How to find the Application Name for a ContentID

While reviewing ConfigMgr status messages for clients reporting problems acquiring package content (Message ID 10025) I found some code snippets on sccmfaq.ch that maps the ContentID to the name of the application. As i had to do several lookups, I decided to create a function for it.

SNAGHTML11ce803

function Get-xCMContentIDforApp
{
<#
.Synopsis
    Get-xCMContentIDforApp
.DESCRIPTION
   This function retrieves the Application name for the provided ContentID. 
   Use this when analyzing status messages (10025) for clients reporting problems
   acquiring package content   

.EXAMPLE
    Get-xCMContentIDforApp -SiteServer cmsrv01 -SiteCode lab -ContentID Content_4783c44a-3f5c-4bf3-a130-a89e5520173a, Content_1d336090-12e4-445b-9c15-718ee5ddf40a

    Application                             ContentID                                      
    -----------                             ---------                                      
    Mozilla Firefox_SW10012130              Content_4783c44a-3f5c-4bf3-a130-a89e5520173a   
    Microsoft Excel 2010 x64_SW10011686_V   Content_1d336090-12e4-445b-9c15-718ee5ddf40a   

    The above example retrieves the Application name for each contentID provided. 

.NOTES
 Credits to sccmfaq.ch where i found the code snippets
#http://sccmfaq.wordpress.com/2014/03/11/sccm-2012-get-from-content-id-to-the-name-of-an-application-with-powershell/
 Version 1.0 by Alex Verboon
#>



[CmdletBinding(SupportsShouldProcess=$true)]
    Param
    (
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        $SiteServer,
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=1)]
        $SiteCode,
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=2)]
        [string[]]$ContentID
    )

Begin{}
Process
{
    $CIDApps = @()

    ForEach ($cid in $ContentID)
    {

    If ($PScmdlet.ShouldProcess("Retrieving Application Name for  $cid"))
    {
        $ContenId01 = (("$cid").Split("."))[0]
        $ApplicationID = (Get-WmiObject -Namespace root\sms\site_$SiteCode -ComputerName $SiteServer -Class SMS_Deploymenttype -Filter "ContentID = '$ContenId01' and PriorityInLatestApp = '1'").AppModelName
        $App = (Get-WmiObject -Namespace root\sms\site_$SiteCode -ComputerName $SiteServer -Class SMS_Application -Filter "CI_UniqueID like '$ApplicationID%' and IsLatest = 'True'").LocalizedDisplayName

        $object = New-Object -TypeName PSObject
        $object | Add-Member -MemberType NoteProperty -Name "Application" -Value $App
        $object | Add-Member -MemberType NoteProperty -Name "ContentID" -Value $cid
        $CIDApps += $object
        }
    }
}
End
{
    $CIDApps | Select-Object Application, ContentID 
}
}


ConfigMgr – PowerShell Script to list Image Binary Delta Replication Setting

Here’s a script that lists all Boot and Operating system images stored within Configuration Manager and shows whether the Binary Delta Replication Setting is enabled or not.

SNAGHTML3132c3

 

<#
.Synopsis
   List Binary Delta Replication Setting for ConfigMgr Boot and Operating System images
.DESCRIPTION
   This cmdlet Lists ConfigMgr the Boot image and Operating System image Binary Delta Replication Setting
.EXAMPLE

.EXAMPLE
   Another example of how to use this cmdlet
.NOTES
 #http://msdn.microsoft.com/en-us/library/hh948196.aspx
 Version 1.0 by Alex Verboon

#>
function Get-CMImgBDRSetting
{
    [CmdletBinding()]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        $SiteCode,
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=1)]
        $SiteServer
    )

    Begin
    {
    [string] $Namespace = "root\SMS\site_$SiteCode"
    $allImages = Get-WmiObject -Namespace $Namespace -ComputerName $SiteServer -Query "SELECT Name, Description, Version,PkgFlags, PackageType  FROM SMS_PackageBaseclass Where PackageType = '258' OR PackageType = '257' "
    $USE_BINARY_DELTA_REP = "0x04000000"
    }
    Process
    {
        $bdr_images = @()
        ForEach ($img in $allImages)
        {
        $object = New-Object -TypeName PSObject
        $object | Add-Member -MemberType NoteProperty -Name "Name" -Value $img.Name
        $object | Add-Member -MemberType NoteProperty -Name "Version" -Value $img.Version
        $object | Add-Member -MemberType NoteProperty -Name "Description" -Value $img.Description
        $object | Add-Member -MemberType NoteProperty -Name "Binary_Delta_Rep" -Value ($ubdr = if($img.PkgFlags -band $USE_BINARY_DELTA_REP) {"Enabled"} Else {"Disabled"})
        $bdr_images += $object
        }
    }
    End
    {
        $bdr_images | Sort-Object Name
    }
}

New Group Policy Settings for Office 365

On April 28th 2014 Microsoft finally released an fix for the Office 2013 SP1 Office customization tool as the version released with SP1 caused some issues with Lync 2013 and OneDrive for Business. But there’s more in this update.A few new Group Policy settings for Office 365 are included as well.

SNAGHTML7561b1

Important. These new Group Policy settings only apply to Office 365 (click to run installations) and not to Office 2013 MSI based installations. The reason for this is because the settings relate to the update mechanism that’s build in to the Office 365 product.

These are the new settings

Setting Description
Hide Update Notifications

This policy setting allows you to hide notifications to users that updates to Office are available.

When automatic updates are enabled for Office, in most cases updates are applied automatically in the background without any user input. However, updates can’t be applied if an Office program is open. If an Office program is open, other attempts are made to apply the updates at a later time. If, after several days, updates haven’t been applied, only then will users see a notification that an update to Office is available.

If you enable this policy setting, users won’t see notifications that updates to Office are ready to be applied.

If you disable or don’t configure this policy setting, users will see notifications that updates to Office are ready to be applied.

This policy setting does not apply to notifications associated with update deadlines.

Important:  This policy setting only applies to Office products that are installed by using Click-to-Run. It doesn’t apply to Office products that use Windows Installer (MSI).

Update Deadline

This policy setting allows you to set a deadline by when updates to Office must be applied.

Prior to the deadline, users will receive multiple reminders to install the updates. If Office isn’t updated by the deadline, the updates are applied automatically. If any Office programs are open, they’ll be closed, which might result in data loss.

We recommend that you set the deadline at least a week in the future to allow users time to install the updates.

If you enable this policy setting, you set the deadline in the format of MM/DD/YYYY HH:MM in Coordinated Universal Time (UTC). For example, 05/14/2014 17:00.

If you disable or don’t configure this policy setting, no deadline is set, unless you specify one by using the Office Deployment Tool.

You can use this policy setting with the Target Version policy setting to ensure that Office is updated to a particular version by a particular date.

The deadline only applies to one set of updates. If you want to ensure that Office is always up-to-date, you need to update the deadline in this policy setting every time a new update for Office is available.

Important:  This policy setting only applies to Office products that are installed by using Click-to-Run. It doesn’t apply to Office products that use Windows Installer (MSI).

Update Path

This policy setting allows you to specify the location where Office will get updates from.

If you enable this policy setting, you can specify one of the following for the update location:  a network share, a folder on the local computer where Office is installed, or an HTTP address. Mapped network drives aren’t supported.

If you enable this policy setting, but you leave the update location blank, Office will get updates from the Internet.

If you disable or don’t configure this policy setting, Office will get updates from the Internet, unless you specify a different location by using the Office Deployment Tool.

Important: This policy setting only applies to Office products that are installed by using Click-to-Run. It doesn’t apply to Office products that use Windows Installer (MSI).

Target Version

This policy setting allows you to specify a version number that you want to update Office to.  For example, version 15.0.4551.1512.

If you enable this policy setting, you specify the version that you want to update Office to. The next time Office looks for updates, Office will try to update to that version. The version must be available where Office is configured to look for updates (for example, on a network share).

If you enable this policy setting, but you leave the version blank, Office is updated to the most current version that’s available at the update location for Office.

If you disable or don’t configure this policy setting, Office is updated to the most current version that’s available at the update location for Office, unless you specify a different version by using the Office Deployment Tool.

Important:  This policy setting only applies to Office products that are installed by using Click-to-Run. It doesn’t apply to Office products that use Windows Installer (MSI).

The latest Office 2013 Administrative Template files (ADMX/ADML) and Office Customization Tool released on 28.04.2014 can be downloaded from here

PowerShell Script – List Scheduled Tasks

Here’s a simple script I put together to list the scheduled tasks including the description, status and whether the task is set to hidden or not. When deploying a new operating system I find it important to understand what scheduled tasks are enabled to run, as sometimes there might be some potential to improvie the systems performance by disabling those you feel are not needed in your environment.

$schtasks = @()
$st = Get-ScheduledTask
ForEach ($SchTask in $st)
{
    $object = New-Object -TypeName PSObject
    $object | Add-Member -MemberType NoteProperty -Name "TaskName" -Value $SchTask.TaskName
    $object | Add-Member -MemberType NoteProperty -Name "Description" -Value $SchTask.Description
    $object | Add-Member -MemberType NoteProperty -Name "State" -Value $SchTask.State
    $object | Add-Member -MemberType NoteProperty -Name "Hidden" -Value $SchTask.Settings.Hidden
    $schtasks += $object
}
$schtasks | Sort-Object "Hidden" -Descending |  Format-list 

Within the Scheduled Tasks UI, by default you will not see the contents of Tasks that are set to hidden. But this can be enabled. Open the Task Scheduler with taskschd.msc and within the View Menu select “Show Hidden Tasks”.

2014-04-28_16h41_50

Managing Windows Defender / System Center Endpoint Security with PowerShell

I just read a blog post from Ed Wilson (Scripting Guy) about Use PowerShell to Configure Windows Defender Preferences and wondered if there’s more here. And yes there is. If you have a default insallation of Windows 8 and have defender enabled or work in an enterprise environment and use Configuration Manager with the  System Center Endpoint Security agent deployed on your clients then you the below listed cmdlets available.

Windows Defender

To get a list of all available Defender cmdlets just run the following command within a powershell console

Get-command -Module defender

System Center Endpoint Protection

For a list of all available SCEP cmdlets, run the following command within a powershell console.

Get-command -Module MpProvider

If no cmdlets are returned try first loading the module using the following command
Import-Module “$env:ProgramFiles\Microsoft Security Client\MpProvider”

You will notice that the cmdlet names are quite similar, the only difference is that the cmdlets for SCEP have “Prot” within the name.

Windows Defender System Center Endpoint Protection
Cmdlet ModuleName Cmdlet ModuleName
Add-MpPreference Defender Add-MProtPreference MpProvider
Get-MpComputerStatus Defender Get-MProtComputerStatus MpProvider
Get-MpPreference Defender Get-MProtPreference MpProvider
Get-MpThreat Defender Get-MProtThreat MpProvider
Get-MpThreatCatalog Defender Get-MProtThreatCatalog MpProvider
Get-MpThreatDetection Defender Get-MProtThreatDetection MpProvider
Remove-MpPreference Defender Remove-MProtPreference MpProvider
Remove-MpThreat Defender Remove-MProtThreat MpProvider
Set-MpPreference Defender Set-MProtPreference MpProvider
Start-MpScan Defender Start-MProtScan MpProvider
Update-MpSignature Defender Update-MProtSignature MpProvider

So what can we do here?

Update definitions

Antivirus and Spyware definitions can be updates as following:

Update-MProtSignature -UpdateSource MicrosoftUpdateServer

Starting a Scan

To start a scan use the following command. Available Scantypes are QuickScan, FullScan and CustomScan)

Start-MProtScan -ScanType QuickScan

When using the CustomScan option an the path must be provied using the -Scanpath parameter

Computer Protection Status

Computer protection status information is retrieved with the following command

Get-MpComputerStatus

Defender / SCEP Settings

Configuration settings can be gathered using

Get-MProtPreference

Find information about actual threat

To find out information about an actual threat on a client, run

Get-MProtThreat

2014-04-08_15h06_33

Removing Threats

Although there is a Remove-MProtThreat cmdlet, it doesn’t seem to recognize the active threat, as i received the following message when executing it.

2014-04-08_15h13_13

Configuration Changes

For configuratin settings, please refer to Ed Wilson’s blog post Use PowerShell to Configure Windows Defender Preferences

That’s it for today, now it has stopped raining and the sun starts to shine, so let’s get out of here Smile

How to export third-party driver packages using PowerShell

Windows 8.1 Update introduces a new cmdlet that allows you to export third-party drivers that are located within the driver store of a Windows client.

$ExpDrv = Export-WindowsDriver -Online -Destination c:\temp\3rdpartydrivers 

The result, all drivers exported into the provided destination directory

2014-04-04_21h36_47

Now we have a whole bunch of folders, but what drivers did we actually export?

$ExpDrv | Select-Object ClassName, ProviderName, Date, Version | Sort-Object ClassName

2014-04-04_21h40_00

For more information read the What’s new in DISM article here

Good to know: System Center 2012 Configuration Pack for Microsoft User Experience Virtualization

Based on a conversation I had yesterday at the ConfigMgr Community event here , it appears that few people know about the existance of the ConfigMgr pack for Microsoft UE-V. There’s one for UE-V version 1.0 and just a few weeks ago one for UE-V 2.0 was released.

After Microsoft User Experience Virtualization (UE-V) and its required components are installed, UE-V must be configured. This UE-V Configuration Pack provides a way for administrators to use the Compliance Settings feature of System Center Configuration Manager 2012 SP1 to apply consistent configuration across sites where UE-V is installed.

The UE-V Configuration Pack for UE-V 2.0 provides tools to do the following:

The UE-V Configuration Pack provides tools to do the following:
1.    Create UE-V template distribution baselines.
a.    Defines UE-V templates to be registered or unregistered
b.    Updates UE-V template configuration items and baselines as templates are added or updated.
c.    Distribute and register UE-V templates using standard Configuration Item remediation

2.    Create an Agent policy configuration item to manage the following settings:
a.    Max package size
b.    Setting import delay
c.    Settings import notification
d.    Settings storage path
e.    Sync enablement
f.    Sync method
g.    Sync timeout
h.    Enable/disable Windows 8 app sync
i.    Sync unlisted Windows 8 apps
j.    IT contact URL
k.    IT contact descriptive text
l.    Tray icon enabled
m.    First use notification
n.    Wait for sync on application start
o.    Wait for sync on logon
p.    Wait for sync timeout
q.    Settings template catalog path
r.    Start/Stop UE-V agent service
s.    Define which Windows 8 apps will roam settings

PowerShell – Finding ConfigMgr Collections and Members

The below script provides a simple and quick method to find ConfigMgr Collections and its members. The script has a -Name parameter that accepts the exact or part of the collection name. Next all collections that match the name are listed. After selecting a collection, its members are listed.

Function Get-CMColContent()
{
<#
.Synopsis
   Get Configuration Manager Collections and Members
.DESCRIPTION
   This script provides an interactive way to find collections and collection members within 
   Configuration Manager. 
.PARAMETER Name
   The exact or partial collection name. 
.EXAMPLE
   Get-CMColContent -Name All
#>


 Param(
    [Parameter(Mandatory=$true,
    ValueFromPipelineByPropertyName=$true,
    HelpMessage="Enter Collection Name or part of collection Name",
    Position=0)]
    [String]$Name
    )

# Change Site Server Name and Site code so it fits your environment
[string] $SiteServer = "servername"
[string] $SiteCode = "010"
[string] $Namespace = "root\SMS\site_$SiteCode"

$CollectionItem = Get-WmiObject -Namespace $Namespace -ComputerName $SiteServer -Query "SELECT Name,LimitToCollectionName,MemberClassName, MemberCount, CollectionType  FROM SMS_Collection WHERE Name LIKE '%$Name%'" | Select-Object Name,LimitToCollectionName,MemberClassName, MemberCount, CollectionType, ResourceID | Sort-Object CollectionType| Out-GridView -Title "Collections" -OutputMode Single

$CollectionType = $CollectionItem.CollectionType
$CollectionName = $CollectionItem.Name
$MemberClassName = $CollectionItem.MemberClassName


If ($CollectionType -eq 2) # Computer collections
    {
        Write-Output "Please wait, this can take a while..."
        $colcontent = Get-WmiObject -Namespace $Namespace -ComputerName $SiteServer -Query "SELECT Name, Active, OperatingSystemNameandVersion, ResourceID FROM SMS_R_SYSTEM where ResourceID in (Select ResourceID from $MemberClassName)" | Select-Object Name, Active, OperatingSystemNameandVersion -wait | Sort-Object Name 
        $colcontent = $colcontent | Out-GridView -Title "Collection: $CollectionName Member Class: $MemberClassName" -OutputMode Multiple
        #return $colcontent
    }
Elseif ($CollectionType -eq 1) # User Collections 
    {
       Write-Output "Please wait, this can take a while..."
       $colcontent = Get-WmiObject -Namespace $Namespace -ComputerName $SiteServer -Query "SELECT UserName, UserPrincipalName, ResourceID FROM SMS_R_USER  where ResourceID in (Select ResourceID from $MemberClassName)" | Select-Object Username, UserPrincipalName, ResourceID -wait
       $colcontent = $colcontent | Out-GridView -Title "Collection: $CollectionName Member Class: $MemberClassName" -OutputMode Multiple 
       #return $colcontent
    }
Else
    {
      Write-output "No support for other Collection Type $Collectiontype"
    }

return $colcontent
}

Example:

Get-CMColContent -Name “All”

SNAGHTMLa17ffb

SNAGHTMLa30678

PowerShell – Retrieve System Startup Time Information

The below script gathers the following system startup time information from a local or remote client.

  • Computername
  • Last Wakeup time (from Sleep, Hibernate or Fast boot on Windows 8x clients)
    The last wakeup date/time is converted from UTC into the client local time.
  • Last Boot time
  • The Time Zone of the client
  • The system wakeup / sleep message from the Windows event log

Important: the script uses PowerShell remoting, it’s therefore required that the targeted clients have WinRM enabled.

Function Get-SystemStartInfo()
 {
 <#
 .Synopsis
 Get System Boot / Wake-up Time 
 .DESCRIPTION
 This script retrieves system boot and wakeup times from the specified client(s). 
 On Windows 8x clients, the last Wake-up time is the last time the system performed a 
 fast boot. 
 .PARAMETER Computer
 The name of one or multiple clients
 .EXAMPLE
 Get-SystemStartInfo localhost, dev001 | Format-Table -AutoSize

 Computer LastWakeupTime LastBootTime TimeZone 
 -------- -------------- ------------ -------- 
 localhost 1/5/2014 11:55:41 PM 1/5/2014 2:35:44 PM (UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm,...
 dev001 1/5/2014 11:55:41 PM 1/5/2014 2:35:44 PM (UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm,...

.NOTES
 WinRM must be enabled on remote clients
 #>
 
[CmdletBinding()]
 Param(
    [Parameter(Mandatory=$true,
    ValueFromPipelineByPropertyName=$true,HelpMessage="Enter Computername(s)",
    Position=0)]
    [Alias("ipaddress","host")]
    [String[]]$Computer
    )

Begin
{
    Function Get-LocalTime($UTCTime,$Comp)
    {
        #Credits to Tao Yang for the Get-LocalTime function
        #http://blog.tyang.org/2012/01/11/powershell-script-convert-to-local-time-from-utc/
        #$strCurrentTimeZone = (Get-WmiObject win32_timezone).StandardName
        $strCurrentTimezone = Get-CimInstance -ComputerName $Comp -Namespace root/CIMV2 -ClassName win32_TimeZone | Select-Object -ExpandProperty StandardName -ErrorAction SilentlyContinue
        $TZ = [System.TimeZoneInfo]::FindSystemTimeZoneById($strCurrentTimeZone) 
        $LocalTime = [System.TimeZoneInfo]::ConvertTimeFromUtc($UTCTime, $TZ)
        Return $LocalTime, $TZ
    }
}
Process
{
    $SystemStartInfo=@()
    foreach ($c in $Computer)
    {
        Write-Output "Processing $c"
        if (Test-Connection -ComputerName $c -Quiet -Count 3 )
        {
            # The last boot date time
            $LBootLocal = Get-CimInstance -ComputerName $c -Namespace root/CIMV2 -ClassName Win32_OperatingSystem -ErrorAction SilentlyContinue | Select -ExpandProperty LastBootuptime -ErrorAction SilentlyContinue
            If([string]::IsNullOrEmpty($LBootLocal) -eq $true)
            {
                # No last boot time found
                $LBootLocal=""
            }
            
            $PowerEvent = Invoke-Command -ComputerName $c -ScriptBlock {
            $orgCulture = Get-Culture
            [System.Threading.Thread]::CurrentThread.CurrentCulture = New-Object "System.Globalization.CultureInfo" "en-US"
            $PowerEvent = Get-WinEvent -ProviderName "Microsoft-Windows-Power-Troubleshooter" -MaxEvents 1 -ErrorAction SilentlyContinue | Where-Object { $_.id -eq 1 } | Select-Object -ExpandProperty  Message -ErrorAction SilentlyContinue
            [System.Threading.Thread]::CurrentThread.CurrentCulture = $orgCulture
            return $PowerEvent
            } 
            
            If($PowerEvent.count -gt 0)
            {
                # Extract the Date / Time information when the system woke up
                $wake = ($PowerEvent.Replace("`n","@").split("@")[3]).replace("Wake Time: ","")
                [string]$utcyear = $wake.Substring(1,4)
                [string]$utcmonth = $wake.Substring(8,2)
                [string]$utcday = $wake.Substring(13,2)
                [string]$utchour = $wake.Substring(16,2)
                [string]$utcminute = $wake.Substring(19,2)
                [string]$utcseconds = $wake.Substring(22,2)
                $wakedt = $utcyear + $utcmonth + $utcday + $utchour + $utcminute + $utcseconds

                $Culture = [System.Globalization.CultureInfo]::InvariantCulture 

                #The datetime in UTC format
                $LWUTC = [datetime]::ParseExact($wakedt,"yyyyMMddHHmmss",$Culture)
                # The datetime in Local Time format
                $LWLocal = Get-LocalTime $LWUTC $c
            }
            Else
            {
                #No last wake up event found, so let's just get the TimeZone information
                $TZName = Get-CimInstance -ComputerName $c -Namespace root/CIMV2 -ClassName win32_TimeZone | Select-Object -ExpandProperty StandardName -ErrorAction SilentlyContinue
                $TZ = [System.TimeZoneInfo]::FindSystemTimeZoneById($TZName) 
                $LWLocal = "","$TZ"
                $PowerEvent = ""
            }

            $object = New-Object -TypeName PSObject
            $object | Add-Member -MemberType NoteProperty -Name "Computer" -Value $c
            $object | Add-Member -MemberType NoteProperty -Name "LastWakeupTime" -Value $LWLocal[0]
            $object | Add-Member -MemberType NoteProperty -Name "LastBootTime" -Value $LBootLocal
            $object | Add-Member -MemberType NoteProperty -Name "TimeZone" -Value $LWLocal[1]
            $object | Add-Member -MemberType NoteProperty -Name "Message" -Value $PowerEvent
            $SystemStartInfo += $object
        }
Else
        {
        Write-Verbose "Unable to connect to $c"
        }
    }
}
End
{
    return $SystemStartInfo 
}
}

Example:

Get-Systemstartupinfo client1,client2,client3,client4,client5, client6 | format-list

Computer       : client1
LastWakeupTime :
LastBootTime   : 24.12.2013 12:28:41
TimeZone       : (UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
Message        :

Computer       : client2
LastWakeupTime : 06.01.2014 08:33:04
LastBootTime   : 06.01.2014 08:29:08
TimeZone       : (UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
Message        : The system has resumed from sleep.
                
                 Sleep Time: ?2014?-?01?-?06T07:32:42.550130000Z
                 Wake Time: ?2014?-?01?-?06T07:33:04.780800500Z
                
                 Wake Source: Device -Intel(R) 82579LM Gigabit Network Connection

Computer       : client3
LastWakeupTime : 29.12.2013 19:17:22
LastBootTime   : 06.01.2014 00:55:57
TimeZone       : (UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi
Message        : The system has resumed from sleep.
                
                 Sleep Time: ?2013?-?12?-?29T11:05:17.427355600Z
                 Wake Time: ?2013?-?12?-?29T11:17:22.762004000Z
                
                 Wake Source: Power Button

Computer       : client4
LastWakeupTime : 06.01.2014 10:03:57
LastBootTime   : 06.01.2014 09:55:36
TimeZone       : (UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
Message        : The system has resumed from sleep.
                
                 Sleep Time: ?2014?-?01?-?06T09:01:05.727399400Z
                 Wake Time: ?2014?-?01?-?06T09:03:57.248801300Z
                
                 Wake Source: Power Button

Computer       : client5
LastWakeupTime : 13.12.2013 13:27:33
LastBootTime   : 06.01.2014 09:28:39
TimeZone       : (UTC) Dublin, Edinburgh, Lisbon, London
Message        : The system has resumed from sleep.
                
                 Sleep Time: ?2013?-?12?-?13T12:32:42.342018800Z
                 Wake Time: ?2013?-?12?-?13T13:27:33.513115200Z
                
                 Wake Source: Device -USB Root Hub

Computer       : client6
LastWakeupTime :
LastBootTime   : 06.01.2014 01:23:48
TimeZone       : (UTC+10:00) Canberra, Melbourne, Sydney
Message        :