Public/Invoke-Clippy.ps1
<#
.Synopsis Notify your users or coworkers with a familiar friend .DESCRIPTION Provides a helpful way to interact with users using Clippy, the beloved Office Assistant from Office '97 .EXAMPLE Invoke-Clippy -text 'Would you like to install Windows 10?' -Button1Text Yes -Button2Text 'Restart PC' Provides a helpful Clippy UI to notify users of the wonders of Windows 10, in case they were unaware. If the user isn't interested, shuts down their PC. .LINK http://www.foxdeploy.com/powerclippy https://github.com/1RedOne/Invoke-Clippy/ .PARAMETER TEXT Contains the text you'd like Clippy to display. Defaults to "Hi! I am Clippy, your office assitant. Would you like some assistance today?" .PARAMETER Button1Text If specified, creates a button for the user to click. Add code to line 70 to make the button function. Include the text you'd like as the value for this param .PARAMETER Button2Text If specified, creates a button for the user to click. Add code to line 81 to make the button function. Include the text you'd like as the value for this param #> Function Invoke-Clippy{ param( $text="Hi! I am Clippy, your office assitant. Would you like some assistance today?", $Button1Text,$Button2Text ) # Add assemblies Add-Type -AssemblyName PresentationFramework, System.Drawing, System.Windows.Forms # Extract icon from PowerShell to use as the NotifyIcon $icon = [System.Drawing.Icon]::ExtractAssociatedIcon("$pshome\powershell.exe") # Create XAML form in Visual Studio, ensuring the ListView looks chromeless [xml]$xaml = '<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="657" Width="525" Background="Transparent" AllowsTransparency="True" WindowStyle="None" Topmost="True"> <Window.Resources> <Style x:Key="ClippyButton" TargetType="Button" > <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Border CornerRadius="5" Background="#FFFFFDCF" BorderThickness="1" Padding="2" BorderBrush="Black"> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </Window.Resources> <Grid Name="grid" Height="200" Width="400"> <ListView Name="listview" SelectionMode="Single" Margin="0,50,0,0" Foreground="White" Background="Transparent" BorderBrush="Transparent" IsHitTestVisible="False"> <ListView.ItemContainerStyle> <Style> <Setter Property="Control.HorizontalContentAlignment" Value="Stretch"/> <Setter Property="Control.VerticalContentAlignment" Value="Stretch"/> </Style> </ListView.ItemContainerStyle> <Image x:Name="image" Height="140" Width="156" Source="C:\git\Invoke-Clippy\Clippy.png"/> </ListView> <Grid x:Name="gr3id" Margin="150,-190,29,190"> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="40"/> </Grid.RowDefinitions> <Rectangle Fill="#FFFFFDCF" Stroke="#FF000000" RadiusX="10" RadiusY="10"/> <Path Fill="#FFFFFDCF" Stretch="Fill" Stroke="#FF000000" HorizontalAlignment="Left" Margin="30,-1.6,0,0" Width="25" Grid.Row="1" Data="M22.166642,154.45381 L29.999666,187.66699 40.791059,154.54395"/> <TextBlock HorizontalAlignment="Center" Name ="ClippyText" VerticalAlignment="Center" FontSize="16" Text="Hi! I am Clippy, your office assitant. Would you like some assistance today?" TextWrapping="Wrap" FontFamily="Arial" Height="88" Margin="2,20,3,52"/> </Grid> <Button Name="button1" Style="{StaticResource ClippyButton}" Content="Button" HorizontalAlignment="Left" Height="38" Margin="278,-78,0,0" VerticalAlignment="Top" Width="75"/> <Button Name="button2" Style="{StaticResource ClippyButton}" Content="Button" HorizontalAlignment="Left" Height="38" Margin="160,-78,0,0" VerticalAlignment="Top" Width="72"/> </Grid> </Window> ' # Turn XAML into PowerShell objects $window = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $xaml)) $xaml.SelectNodes("//*[@Name]") | ForEach-Object { Set-Variable -Name ($_.Name) -Value $window.FindName($_.Name) -Scope Script } # Set textbox content and button text and behavior $ClippyText.Text = $text if ($Button1Text){ $button1.Content = $Button1Text $button1.Visibility = 'Hidden' $button1.add_Click({ #code to execute when the second button is clicked }) } if ($Button2Text){ $button2.Content = $Button2Text $button2.Visibility = 'Hidden' $button2.add_Click({ #code to execute when the second button is clicked }) } # Create notifyicon, and right-click -> Exit menu $notifyicon = New-Object System.Windows.Forms.NotifyIcon $notifyicon.Text = "Clippy" $notifyicon.Icon = $icon $notifyicon.Visible = $true $menuitem = New-Object System.Windows.Forms.MenuItem $menuitem.Text = "Exit" $contextmenu = New-Object System.Windows.Forms.ContextMenu $notifyicon.ContextMenu = $contextmenu $notifyicon.contextMenu.MenuItems.AddRange($menuitem) # Add a left click that makes the Window appear in the lower right # part of the screen, above the notify icon. $notifyicon.add_Click({ if ($_.Button -eq [Windows.Forms.MouseButtons]::Left) { # reposition each time, in case the resolution or monitor changes $window.Left = $([System.Windows.SystemParameters]::WorkArea.Width-$window.Width) $window.Top = $([System.Windows.SystemParameters]::WorkArea.Height-$window.Height) $window.Show() $window.Activate() } }) # Close the window if it's double clicked $window.Add_MouseDoubleClick({ $window.Hide() }) # Close the window if it loses focus $window.Add_Deactivated({ start-sleep -Milliseconds 500 $window.Hide() }) # When Exit is clicked, close everything and kill the PowerShell process $menuitem.add_Click({ $notifyicon.Visible = $false $window.Close() Stop-Process $pid }) # Make PowerShell Disappear $windowcode = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);' $asyncwindow = Add-Type -MemberDefinition $windowcode -name Win32ShowWindowAsync -namespace Win32Functions -PassThru $null = $asyncwindow::ShowWindowAsync((Get-Process -PID $pid).MainWindowHandle, 0) # Force garbage collection just to start slightly lower RAM usage. [System.GC]::Collect() # Create an application context for it to all run within. # This helps with responsiveness, especially when clicking Exit. $appContext = New-Object System.Windows.Forms.ApplicationContext [void][System.Windows.Forms.Application]::Run($appContext) } |