Thursday, July 18, 2013

PowerShell and RSS feeds

With google reader shutting down and with the crazy amount of rss feeds available I became curious about what an rss feed actually is.
I was amazed at how basic this whole rss feed process really is.  For instance to display the necessary xml from the latest technology news item on CBC you could run this command.
$([xml]$(New-Object System.Net.WebClient).DownloadString(“http://rss.cbc.ca/lineup/technology.xml”)).rss.channel.item[0]
This really is not formatted too nicely but it gives you the idea how easy it is to get rss feed data from online sources using powershell.

Using rss feeds I created comandlets to get a variety of information that is online. At the bottom of this post is a "Get-Weather" commandlet I added to my profile to easily display the weather forecast.

To get the weather for Houston Texas run:
Get-Weather -City Houston -Province Texas -Country US
For my current location I run:
Get-Weather

function Get-Weather {
[CmdletBinding()]
Param(  [String]$City = "Melville",
        [string]$Province = "Saskatchewan",
        [string]$Country = "Canada")
    
    if($City.Equals("Melville",[System.StringComparison]::InvariantCultureIgnoreCase) -and $Province.Equals("Saskatchewan",[System.StringComparison]::InvariantCultureIgnoreCase)) {
        $LocAbrev = "cask0200"
    }
    else {
        if($Country.Equals("US",[System.StringComparison]::InvariantCultureIgnoreCase)){$Country = "United-States"}
        [System.Reflection.Assembly]::LoadWithPartialName("System.web") | Out-Null
        $SiteUrl = “http://www.theweathernetwork.com/weather/$Country/$Province/$City”
        $Location = (New-Object System.Net.WebClient).DownloadString($SiteUrl)
        [string[]]$Test = '<script>window._uf={};window._uf.p='
        $LocAbrev = $Location.split($Test,[system.StringSplitOptions]::None)[1].split(';')[0].trim('"')
    }

    #Get The Weather From the Weather Networks RSSFeed
    [System.Reflection.Assembly]::LoadWithPartialName("System.web") | Out-Null
    $SiteUrl = “http://rss.theweathernetwork.com/weather/$LocAbrev”
    [xml]$weather = (New-Object System.Net.WebClient).DownloadString($SiteUrl)
    write-Host $weather.rss.channel.title
    foreach($Day in $weather.rss.channel.GetElementsByTagName("item")) {
       Write-Host "Date:       " $Day.title
       Write-Host "Description: " -NoNewline
       $counter = 0
       foreach($Desc in $Day.description.split(',') ) {
             if ($counter++ -ge 1) {Write-host "             " -NoNewline}
             if(![string]::IsNullOrWhiteSpace($Desc.Trim()) -and ![string]::IsNullOrEmpty($Desc.Trim())) {
                 [System.Web.HttpUtility]::HtmlDecode($Desc.Trim());
             
             }
       }
       Write-host ""
    }

Saturday, May 18, 2013

Place Outlook Reminders as top window using C#


Place Outlook Reminders as top window using C#

This program subscribes to WMI events and therefore must be run as an admin account.  It can be added to scheduled jobs so it runs automatically.

It is created as a console application and hides its console window to run in the background.
Basically it watches for whenever Outlook kicks off a new thread and if the window heading has Reminder in it, it forces the window to be on top of all others.

using System;
using System.Management;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace OutlookReminder
{
    class Program
    {
        ManagementEventWatcher startThreadWatch;

        static void Main(string[] args)
        {
            //create a processwatcher that will watch for outlook programs that will be getting opened.
            ProcessWatcher processWatcher = new ProcessWatcher("OUTLOOK.EXE");
            //create a list of threadWatchers for each outlook program that is currently open, however...there really should only be one open at a time.
            List<ThreadsWatcher> threadsWatcher = Process.GetProcessesByName("OUTLOOK").ToList().Select(x => new ThreadsWatcher(x.Id)).ToList();
            
            //Hide this console window and let it live in the background.
            WindowControl.ShowWindow(Process.GetCurrentProcess().MainWindowHandle, (int)WindowControl.WindowState.Hide);
            Console.WriteLine("Press ENTER to stop the Outlook reminders to be forced as the top most window.");
            Console.ReadLine();

            //Dispose of the process watcher that is watching for the outlook program to get opened.
            processWatcher.Dispose();
            //Dispose of all the threads that are not null and not disposed of yet.
            threadsWatcher.Where(x => x != null && !x.disposed).ToList().ForEach(x => x.Dispose());
        }
    }
    #region watchers
    public class ProcessWatcher : IDisposable
    {
        ManagementEventWatcher startProcessWatch;
        ManagementEventWatcher stopProcessWatch;
        ThreadsWatcher threadWatcher;
        public string processName { get; private set; }
        public bool disposed { get; private set; }
        public ProcessWatcher(string _processName)
        {
            processName = _processName;
            disposed = false;
            startProcessWatch = new ManagementEventWatcher(new WqlEventQuery(string.Format("Select * from Win32_ProcessStartTrace WHERE ProcessName='{0}'", processName)));
            startProcessWatch.EventArrived += new EventArrivedEventHandler(startProcessWatch_EventArrived);
            startProcessWatch.Start();
            stopProcessWatch = new ManagementEventWatcher(new WqlEventQuery(string.Format("Select * from Win32_ProcessStopTrace WHERE ProcessName='{0}'", processName)));
            stopProcessWatch.EventArrived += new EventArrivedEventHandler(stopProcessWatch_EventArrived);
            stopProcessWatch.Start();
        }
        #region disposeAndFinalize
        ~ProcessWatcher()
        {
            if (startProcessWatch != null)
            {
                startProcessWatch.Stop();
            }
        }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    startProcessWatch.Stop();
                    startProcessWatch.Dispose();
                    if (threadWatcher != null && !threadWatcher.disposed)
                    {
                        threadWatcher.Dispose();
                    }
                }
                disposed = true;
            }
        }
        #endregion disposeAndFinalize
        void stopProcessWatch_EventArrived(object sender, EventArrivedEventArgs e)
        {
            if (threadWatcher != null && !threadWatcher.disposed)
            {
                threadWatcher.Dispose();
            }
        }
        void startProcessWatch_EventArrived(object sender, EventArrivedEventArgs e)
        {
            int processID = 0;
            int.TryParse(e.NewEvent.Properties["ProcessID"].Value.ToString(), out processID);
            threadWatcher = new ThreadsWatcher(processID);
        }
    }
    public class ThreadsWatcher : IDisposable
    {
        ManagementEventWatcher startThreadWatch;
        public bool disposed { get; private set; }
        public int processID { get; private set; }
        #region constructors
        public ThreadsWatcher(int _processID)
        {
            disposed = false;
            processID = _processID;
            startThreadWatch = new ManagementEventWatcher(new WqlEventQuery("Select * from Win32_ThreadStartTrace WHERE ProcessID=" + processID));
            startThreadWatch.EventArrived += new EventArrivedEventHandler(startThreadWatch_EventArrived);
            startThreadWatch.Start();
        }
        #endregion constructors
        #region disposeAndFinalize
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    startThreadWatch.Stop();
                    startThreadWatch.Dispose();
                }
                disposed = true;
            }
        }
        ~ThreadsWatcher()
        {
            if (startThreadWatch != null)
            {
                startThreadWatch.Stop();
            }
        }
        #endregion disposeAndFinalize
        void startThreadWatch_EventArrived(object sender, EventArrivedEventArgs e)
        {
            int processID = 0;
            int.TryParse(e.NewEvent.Properties["ProcessID"].Value.ToString(), out processID);
            Process outlookProcess = Process.GetProcessById(processID);

            if (outlookProcess.MainWindowTitle.Contains("Reminder"))
            {
                //Place window as TopMost window.
                WindowControl.SetWindowPos(outlookProcess.MainWindowHandle, WindowControl.SpecialWindowHandles.TopMost, 0, 0, 0, 0, WindowControl.SetWindowPosFlags.TopMostFlag);

                //The next 2 commands are use to ensure that if the window is minimized it will still be maximized and displayed.
                //force the window as the foreground window.
                WindowControl.SetForegroundWindow(outlookProcess.MainWindowHandle);
                //Restore the window to be maximized 
                WindowControl.ShowWindow(outlookProcess.MainWindowHandle, (int)WindowControl.WindowState.Restore);
            }
            outlookProcess.Dispose();
        }
    }
    #endregion watchers
    static class WindowControl
    {
        #region WindowControlEnums
        //First few classes are defined to replace an enum however defining it this way we can load any type.
        public static class SpecialWindowHandles
        {
            public static IntPtr
            NoTopMost = new IntPtr(-2),
            TopMost = new IntPtr(-1),
            Top = new IntPtr(0),
            Bottom = new IntPtr(1);
        }
        public static class SetWindowPosFlags
        {
            public static readonly uint
            NoSize = 0x0001,
            NoMove = 0x0002,
            NoZOrder = 0x0004,
            NoRedraw = 0x0008,
            NoActivate = 0x0010,
            DrawFrame = 0x0020,
            FrameChanged = 0x0020,
            ShowsWindow = 0x0040,
            HideWindow = 0x0080,
            NoCopyBits = 0x0100,
            NoOwnerZOrder = 0x0200,
            NoRrPosition = 0x0200,
            NoSendChanging = 0x0400,
            DeferErase = 0x2000,
            AsyncWindowPos = 0x4000,
            TopMostFlag = NoMove | NoSize;
        }

        //Loaded this great enum values from http://www.pinvoke.net/default.aspx/user32.showwindow.  It loads the XML descriptions so you can read
        //the description in the code when you are using it.
        public enum WindowState :uint
        {
            Hide = 0,
            /// <summary>Activates and displays a window. If the window is minimized 
            /// or maximized, the system restores it to its original size and 
            /// position. An application should specify this flag when displaying 
            /// the window for the first time.</summary>
            /// <remarks>See SW_SHOWNORMAL</remarks>
            ShowNormal = 1,
            /// <summary>Activates the window and displays it as a minimized window.</summary>
            /// <remarks>See SW_SHOWMINIMIZED</remarks>
            ShowMinimized = 2,
            /// <summary>Activates the window and displays it as a maximized window.</summary>
            /// <remarks>See SW_SHOWMAXIMIZED</remarks>
            ShowMaximized = 3,
            /// <summary>Maximizes the specified window.</summary>
            /// <remarks>See SW_MAXIMIZE</remarks>
            Maximize = 3,
            /// <summary>Displays a window in its most recent size and position. 
            /// This value is similar to "ShowNormal", except the window is not 
            /// actived.</summary>
            /// <remarks>See SW_SHOWNOACTIVATE</remarks>
            ShowNormalNoActivate = 4,
            /// <summary>Activates the window and displays it in its current size 
            /// and position.</summary>
            /// <remarks>See SW_SHOW</remarks>
            Show = 5,
            /// <summary>Minimizes the specified window and activates the next 
            /// top-level window in the Z order.</summary>
            /// <remarks>See SW_MINIMIZE</remarks>
            Minimize = 6,
            /// <summary>Displays the window as a minimized window. This value is 
            /// similar to "ShowMinimized", except the window is not activated.</summary>
            /// <remarks>See SW_SHOWMINNOACTIVE</remarks>
            ShowMinNoActivate = 7,
            /// <summary>Displays the window in its current size and position. This 
            /// value is similar to "Show", except the window is not activated.</summary>
            /// <remarks>See SW_SHOWNA</remarks>
            ShowNoActivate = 8,
            /// <summary>Activates and displays the window. If the window is 
            /// minimized or maximized, the system restores it to its original size 
            /// and position. An application should specify this flag when restoring 
            /// a minimized window.</summary>
            /// <remarks>See SW_RESTORE</remarks>
            Restore = 9,
            /// <summary>Sets the show state based on the SW_ value specified in the 
            /// STARTUPINFO structure passed to the CreateProcess function by the 
            /// program that started the application.</summary>
            /// <remarks>See SW_SHOWDEFAULT</remarks>
            ShowDefault = 10,
            /// <summary>Windows 2000/XP: Minimizes a window, even if the thread 
            /// that owns the window is hung. This flag should only be used when 
            /// minimizing windows from a different thread.</summary>
            /// <remarks>See SW_FORCEMINIMIZE</remarks>
            ForceMinimized = 11
        }

        #endregion

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.I4)]
        public static extern int SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
    }
}