Using PowerShell to Analyze Your PC’s Sleep & Wake Behavior

I have some older hardware running Windows 7 Media Center.  Normally we let the Media Center just go to sleep on its own but I’ve been concerned that it isn’t sleeping as much during there wee hours of the morning as I think it should be.  I’ve got Ceton quad tuner card in it that I like to give a chance to cool down.  The one problem with our slim form factor Media Center PC is that the cooling isn’t the best.

In order to determine how much the PC sleeps I wrote a small PowerShell script to analyze event log entries.  Here are the contents of the script Get-SleepInfo.ps1:

param($Newest = 50)

function Parse-EventLogEntry
{
    param(
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [System.Diagnostics.EventLogEntry[]]
        $eventInfo
    )

    Process
    {
        foreach ($info in $eventInfo)
        {
            $enterSleep = [DateTime]::Parse($info.ReplacementStrings[0]);
            $exitSleep = [DateTime]::Parse($info.ReplacementStrings[1]);
            $duration = $exitSleep - $enterSleep
            $wakeSource = 'Unknown'
            if ($info.Message -match 'Wake Source:\s*(.*)$')
            {
                $wakeSource = $matches[1]
            }
            new-object psobject -Property @{Duration = $duration; Sleep = $enterSleep; 
                                            Wake = $exitSleep; WakeSource = $wakeSource}
        }
    }
}

Get-EventLog -LogName System -Source Microsoft-Windows-Power-Troubleshooter -Newest $Newest | 
     Sort TimeGenerated | Parse-EventLogEntry

 

After running this on my MediaCenter PC, I get the following data:

Duration         Sleep                Wake                 WakeSource
--------         -----                ----                 ----------
01:04:22.2225162 5/2/2013 2:47:08 PM  5/2/2013 3:51:31 PM  5Windows will exec...
00:44:42.9902954 5/3/2013 12:33:23 AM 5/3/2013 1:18:06 AM  5Windows will exec...
00:12:56.0674401 5/3/2013 2:18:08 AM  5/3/2013 2:31:05 AM  5Windows will exec...
06:59:43.2874463 5/3/2013 3:31:08 AM  5/3/2013 10:30:52 AM 0
05:54:48.3185846 5/4/2013 5:01:08 AM  5/4/2013 10:55:57 AM 0
00:30:09.8591193 5/5/2013 1:15:01 AM  5/5/2013 1:45:11 AM  5Windows will exec...
05:30:49.2332622 5/5/2013 5:01:04 AM  5/5/2013 10:31:54 AM 0
03:12:13.2579267 5/6/2013 5:02:20 AM  5/6/2013 8:14:33 AM  0
00:14:30.6312742 5/7/2013 1:25:14 AM  5/7/2013 1:39:45 AM  5Windows will exec...
00:11:23.6864251 5/7/2013 2:39:59 AM  5/7/2013 2:51:23 AM  5Windows will exec...
04:18:45.8838138 5/7/2013 4:34:44 AM  5/7/2013 8:53:30 AM  0
01:19:03.7671589 5/7/2013 12:46:44 PM 5/7/2013 2:05:48 PM  0
00:37:13.6740184 5/8/2013 12:59:29 AM 5/8/2013 1:36:43 AM  5Windows will exec...
00:01:11.1209186 5/8/2013 2:36:57 AM  5/8/2013 2:38:09 AM  5Windows will exec...
02:13:18.0939494 5/8/2013 3:38:12 AM  5/8/2013 5:51:31 AM  5Windows will exec...

 

The problematic wake source above (truncated in this output to fit the blog post width) is:

5Windows will execute ‘\Microsoft\Windows\Media Center\mcupdate_scheduled’ scheduled task that requested waking the computer.

Ah, good ol’ mcupdate_scheduled is configured to wake the computer if it is asleep.  This situation is quickly fixed with a little tweak to the scheduled task to a) not wake the computer and b) change the trigger to a time the computer is likely to be on.  With this tweak hopefully the MediaCenter will now sleep through the night.

Update: after tweaking the scheduled task “mcupdate_scheduled”, my Media Center PC slept for a good 12 hours before *I* woke it up:

02:13:18.0939494 5/8/2013 3:38:12 AM  5/8/2013 5:51:31 AM  5Windows will exec...
12:15:24.3601661 5/9/2013 1:24:42 AM  5/9/2013 1:40:07 PM  0
Posted in PowerShell | 1 Comment

PowerShell Script that Relaunches as Admin

If were following good security practices we run our Windows system with UAC enabled.  This means that if you forget to launch your PowerShell prompt as Administrator when you run a script that requires administrative privilege then that script will fail.

It would be nice to build a mechanism into our script to “auto-elevate” if UAC is enabled.  The trick to doing this is to run Start-Process –verb runas.  After that you only need to figure out if the current user is an administrator and if UAC is enabled.  And you have to package up the script’s parameters as an array of strings.  All of this can be accomplished fairly easily with this bit of PowerShell script:

function IsAdministrator
{
$Identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$Principal = New-Object System.Security.Principal.WindowsPrincipal($Identity)
$Principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
}


function IsUacEnabled
{
(Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System).EnableLua -ne 0
}

#
# Main script
#
if (!(IsAdministrator))
{
if (IsUacEnabled)
{
[string[]]$argList = @('-NoProfile', '-NoExit', '-File', $MyInvocation.MyCommand.Path)
$argList += $MyInvocation.BoundParameters.GetEnumerator() | Foreach {"-$($_.Key)", "$($_.Value)"}
$argList += $MyInvocation.UnboundArguments
Start-Process PowerShell.exe -Verb Runas -WorkingDirectory $pwd -ArgumentList $argList
return
}
else
{
throw "You must be administrator to run this script"
}
}

If you launch this script from a non-elevated context, it will fire up a new PoweShell session that is elevated assuming UAC is enabled.

Posted in PowerShell | 8 Comments

Windows PowerShell V3 Language Specification Posted

You can download it here.

Posted in PowerShell 3.0 | Leave a comment

PSCX 2.1 and 3.0 Release Candidates Posted

Oisin and I have been busy prepping the PowerShell Community Extensions to support Windows PowerShell 3.0.  With this release, we are providing two packages.  There is a Pscx-2.1.0-RC.zip that is xcopy deployable just like PSCX 2.0.  Just remember to unblock the ZIP before extracting it otherwise you’ll get errors when you try to import the module.  Pscx 2.1 can be used to target both Windows PowerShell 2.0 and 3.0.  In order to do this, Pscx 2.1 is still compiled against .NET 2.0 and it can’t take advantage of any Windows PowerShell 3.0 specific features. 

The second package is Pscx-3.0.0-RC.msi.  This is a traditional Windows installer package.  The benefit of using an MSI is that the user doesn’t have to worry about unblocking the file before installing it.  The MSI file is also Authenticode signed with an extended validation code signing certificate so it should make it past Windows 8 SmartScreen.  I’d like to extend a big thanks to DigiCert for graciously donating the EV code signing certificate to us.

INSTALLATION NOTE: the WiX-based installer modifies the PSModulePath environment variable but the modification doesn’t always seem to be in effect after installation.  If Import-Module Pscx –RequiredVersion 3.0.0.0 fails to load PSCX, import the module by path (C:\Program Files (x86)\PowerShell Community Extensions\Pscx3\Pscx\Pscx.psd1) until you get a chance to reboot.  After that, you shouldn’t have to specify the path.

Another aspect of Pscx 3.0 is that it is compiled against .NET 4.0 and takes advantage of some features specific to Windows PowerShell 3.0.  Over time, we will focus our new feature efforts on the Pscx 3.0 branch.

PSCX 2.1 and 3.0 Side-by-Side Support

With this release, you can install Pscx 2.1 and 3.0 side-by-side.  Note however that if you xcopy install Pscx 2.1 into your user’s Modules directory, PowerShell will find that version of Pscx before the 3.0 version.  In order to ensure you load a specific version of Pscx, use the –RequiredVersion parameter on Import-Module e.g.

Import-Module Pscx -RequiredVersion 3.0.0.0

Support for AllSigned Execution Policy

Each of the two packages above (2.1 and 3.0) supported execution in an AllSigned environment.  All of the script files (*.ps1, *.psm1 and *.ps1xml) have been signed.  Of course, this means you can’t modify these scripts (i.e. to fix bugs) and still run them AllSigned.

New Features

There are not a lot of new features in this release but there are a few handy additions including:

  • Get-Parameter – thanks to Jason Archer for contributing this great way to visual a command’s parameter information.
  • Import-VisualStudioVars – for developers who like to spend their time in PowerShell instead of cmd.exe, this function takes care of importing the build environment for the specified version of Visual Studio.  The 2008, 2010 and 2012 versions of Visual Studio are supported.
  • Start-PowerShell – a wrapper for PowerShell.exe that utilizes the PowerShell parameter parsing engine to make invocation of various flavors of PowerShell (from PowerShell obviously) easier.  While testing the AllSigned support I used this command a lot:
    Start-PowerShell -NoProfile -ExecutionPolicy AllSigned -Version 2
  • Get-ExecutionTime – since PowerShell 2.0, the HistoryInfo object for a command has included both the StartExecutionTime and the EndExecutionTime. This command makes it easy to see the total execution time for any command e.g.:

C:\PS> Get-ExecutionTime

  Id ExecutionTime    HistoryInfo
  -- -------------    -----------
   1 00:00:02.9919258 Get-ChildItem C:\Windows\System32
   2 00:00:00.2650339 Get-Process
   3 00:00:00.2499424 Get-Service

Bug Fixes

Oisin spent a good deal of time fixing issues in the Read-Archive and Expand-Archive cmdlets.  We updated the version of 7z that we are using (to 9.x) and modified the cmdlets to use SevenZipSharp.  I also fixed a number of bugs in Invoke-Elevated (alias su), Set-Writable, Edit-File and type accelerators breaking on PowerShell 3.0.

As you use these release candidates please report any issues to the Pscx CodePlex project.  Thanks for supporting Pscx!

Posted in PowerShell 2.0, PowerShell 3.0, PSCX | 3 Comments

PSCX 3.0 Beta Released

We’ve just released a beta of the PowerShell Community Extensions 3.0 which targets PowerShell 3.0 specifically.  This new version uses a WiX based installer.  We may look at providing an xcopy deployable ZIP file but we had so many users get burned by not unblocking the ZIP file that the move back to MSI seemed warranted.  The MSI really doesn’t do much other than copy files into the Program Files dir and add a path to the PSModulePath environment variable. 

Be sure to read the installation notes on the download page.  If you’re having problems importing the PSCX module, you might need to reboot.  Yeah I know that sucks but either WiX 3.6 just isn’t handling environment variable updates quite right or I’m not using WiX right. 

If you’re using PSCX and Windows PowerShell 3.0, please take this version for a spin.  You can use it side-by-side with your current version of PSCX 2.x.  When you import PSCX specify the RequiredVersion parameter as shown below e.g.:

Import-Module pscx –RequiredVersion 3.0.0.0

And please, report problems back to the CodePlex site.  I haven’t always been able to reply quickly to issues but we do monitor them.  Thanks!

Posted in PowerShell 3.0, PSCX | 1 Comment

PowerShell V3 – ObsoleteAttribute

PowerShell V3 now supports the ObsoleteAttribute for compiled cmdlets but unfortunately not advanced functions.  This is handy to let your users know that a binary cmdlet will be going away in a future release of your binary module.

As we work on PSCX 3.0 there are a few binary cmdlets that we will mark with this attribute to let you know to switch over to PowerShell’s built-in equivalent before we eliminate the cmdlet completely in the next release.  Here’s a snippet that shows how to apply the ObsoleteAttribute in your source code:

1 [OutputType(typeof(MailMessage))] 2 [Cmdlet(VerbsCommunications.Send, PscxNouns.SmtpMail, 3 DefaultParameterSetName = "Authenticated", 4 SupportsShouldProcess = true)] 5 [Obsolete(@"The PSCX\SendSmtpMail cmdlet is obsolete " + 6 "and will removed in the next version of " + 7 "PSCX. Use the built-in Send-MailMessage.")] 8 public class SendSmtpMailCommand : PscxCmdlet 9 {

The resulting of executing this cmdlet with PSCX v3 loaded is:

C:\PS> Send-SmtpMail
WARNING: The PSCX\SendSmtpMail cmdlet is obsolete and will removed in the next version of 
PSCX. Use the built-in Send-MailMessage.

There is an ObsoleteAttribute constructor overload that takes a boolean that converts the warning to an error.  I’m not sure how useful that is but PowerShell does honor that setting and will generate a terminating error in this case:

C:\PS> Send-SmtpMail
The PSCX\SendSmtpMail cmdlet is obsolete and will removed in the next version of PSCX. Use 
the built-in Send-MailMessage. At line:1 char:1 + Send-SmtpMail + ~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (Send-SmtpMail:String) [], RuntimeException + FullyQualifiedErrorId : UseOfDeprecatedCmdlet

It’s nice to see PowerShell honoring more of the .NET attributes – where it makes sense that is.

Posted in PowerShell 3.0 | Leave a comment

PowerShell V3 Beta–Better NTFS Alternate Data Stream Handling

One of the many new features in Windows PowerShell V3 is better support for alternate data streams (ADS) in NTFS files.  ADS allows an NTFS file to contain additional data that is not part of the “main” stream i.e. the file’s primary content.  Tools like Windows Explorer or even PowerShell’s Get-ChildItem cmdlet don’t show these extra data streams.  In fact the file size reported by both of these tools does not take into account the data stored in the alternate streams.  For more information on ADS check out the NTFS topic on Wikipedia.

A common use of ADS is to indicate that a file downloaded by Internet Explorer came from the Internet Zone.  Files coming from the internet could be potentially dangerous.  Various applications check for this stream and if it is present and contains information indicating the “Internet” zone, they might block access or in the case of PowerShell’s RemoteSigned execution policy, only execute the file if it is signed.

Previous to PowerShell V3, you could use the SysInternals streams.exe tool to list and remove alternate data streams.  A common application of this tool was to delete all streams in a file.  That was a rather crude but effective way to “unblock” a file downloaded from the internet.

This is also one area where CMD.EXE was one up on PowerShell.  From a CMD prompt, you can use “dir /r” to list files and their alternate data streams.  You can also create/overwrite streams with CMD.exe like so “echo.>test.exe:Zone.Identifier” which would “unblock” an internet zone file.  You can also unblock such files by selecting the file’s Properties in Windows Explorer and pressing the “Unblock” button at the bottom right of the general tab.  However this is not convenient if you need to do this to dozens or hundreds of files.  With the PowerShell Community Extensions 2.0, we introduced an Unblock-File cmdlet that would delete only the stream named Zone.Identifier.  That is the stream that Internet Explorer creates when you download a file.  Fortunately with PowerShell V3, we can obsolete that cmdlet because V3 offers several ways to manage alternate data streams.

First up is PowerShell’s own Unblock-File cmdlet which, like the PSCX equivalent, is quite easy to use:

C:\PS> Get-Command Unblock-File -All

Capability      Name   ModuleName
----------      ----                                     ----------
Cmdlet          Unblock-File                             Pscx
Cmdlet          Unblock-File                             Microsoft.PowerShell.Utility

C:\PS> Get-ChildItem *.ps1 | Microsoft.PowerShell.Utility\Unblock-File

Note that you wouldn’t normally need to prefix Unblock-File with Microsoft.PowerShell.Utility.  In this case, I wanted to make sure I was using the PowerShell Unblock-File and not the one from PSCX.

In addition to using the big gun of Unblock-File you can also manipulate streams with the following cmdlets:

C:\PS> Get-Command -ParameterName Stream | Where ModuleName -match 'Microsoft.*?Manag' 

Capability Name          ModuleName
---------- ----          ----------
Cmdlet     Add-Content   Microsoft.PowerShell.Management
Cmdlet     Clear-Content Microsoft.PowerShell.Management
Cmdlet     Get-Content   Microsoft.PowerShell.Management
Cmdlet     Get-Item      Microsoft.PowerShell.Management
Cmdlet     Remove-Item   Microsoft.PowerShell.Management
Cmdlet     Set-Content   Microsoft.PowerShell.Management

Here is how you can list all the alternate data streams in a file and the contents of any particular data stream:

C:\PS> Get-Item .\Pscx-2.0.0.1.zip -Stream *

   FileName: C:\Users\Keith\Downloads\Pscx-2.0.0.1.zip

Stream                   Length
------                   ------
:$DATA                  1799345
Zone.Identifier              26

C:\PS> Get-Content .\Pscx-2.0.0.1.zip -Stream Zone.Identifier
[ZoneTransfer]
ZoneId=3

Note that :$DATA is the main stream i.e. the file’s primary contents.

If you need to clear the contents of a data stream without removing the stream completely, you can use Clear-Content’s –Stream parameter e.g.:

C:\PS> Clear-Content .\Pscx-2.0.0.1.zip -Stream Zone.Identifier
C:\PS> Get-Content .\Pscx-2.0.0.1.zip -Stream Zone.Identifier
C:\PS> Get-Item .\Pscx-2.0.0.1.zip -Stream *

   FileName: C:\Users\Keith\Downloads\Pscx-2.0.0.1.zip

Stream                   Length
------                   ------
:$DATA                  1799345
Zone.Identifier               0

To completely remove the stream, use Remove-Item’s –Stream parameter e.g.:

C:\PS> Remove-Item .\Pscx-2.0.0.1.zip -Stream Zone.Identifier
C:\PS> Get-Item .\Pscx-2.0.0.1.zip -Stream *

   FileName: C:\Users\Keith\Downloads\Pscx-2.0.0.1.zip

Stream                   Length
------                   ------
:$DATA                  1799345

And if you need to create an alternate stream, you can do so using Add-Content’s –Stream parameter e.g.:

C:\PS> Add-Content Pscx-2.0.0.1.zip -Str Zone.Identifier "[ZoneTransfer]`r`nZoneId=3"
C:\PS> Get-Item Pscx-2.0.0.1.zip -Stream *

   FileName: C:\Users\Keith\Downloads\Pscx-2.0.0.1.zip

Stream                   Length
------                   ------
:$DATA                  1799345
Zone.Identifier              26

C:\PS> Get-Content .\Pscx-2.0.0.1.zip -Stream Zone.Identifier
[ZoneTransfer]
ZoneId=3

Finally, Set-Content –Stream can be used to modify the content of an existing stream.

The new  Unblock-File cmdlet as well as the upgrades to the *-Content and Get/Remove-Item  cmdlets are a very welcome enhancement to PowerShell’s file handling capabilities.

Posted in PowerShell 3.0 | 7 Comments