Write a GUI in Powershell – Part 7

7. Finish every else in Powershell. This script will run the timer. Once the time is reached, it will run the command.

# (C) Chao Liu
#===========================================================================
# Add CSharp Class to PowerShell
#===========================================================================

$path=$PSScriptRoot
$code=Get-Content -Raw -Path (Join-Path $path "PowerManagerNS.cs")
Add-Type -TypeDefinition $code

$csharp1=Get-Content (Join-Path $path "DynamicViewModel.cs") -Raw
#$csharp1=Get-Content "d:\Programming\XAML For PS\XAML For PS\DynamicDictViewModel.cs" -Raw
Add-Type -TypeDefinition $csharp1

#Add-Type -AssemblyName PresentationFramework
$csharp2=Get-Content (Join-Path $path "ConverterWrap.cs") -Raw
Add-Type -TypeDefinition $csharp2 -ReferencedAssemblies @("PresentationFramework";"WindowsBase")

$csharp3=Get-Content (Join-Path $path "MultiValueConverterWrap.cs") -Raw
Add-Type -TypeDefinition $csharp3 -ReferencedAssemblies @("PresentationFramework";"WindowsBase")

#===========================================================================
# Store Form Objects In PowerShell
#===========================================================================
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$xaml = Get-Content -Raw -Path (Join-Path $path "autoshutdown.xaml")

#Read XAML
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
catch{Write-Host "Unable to load Windows.Markup.XamlReader. Some possible causes for this problem include: .NET Framework is missing PowerShell must be launched with PowerShell -sta, invalid XAML code was encountered."; exit}

$manager = New-Object System.Xml.XmlNamespaceManager $xaml.NameTable;
$manager.AddNamespace("xaml", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
$manager.AddNamespace("x", "http://schemas.microsoft.com/winfx/2006/xaml");
$xaml.SelectNodes("//*[@x:Name]", $manager ) | %{Set-Variable -Name ($_.Name) -Value $Form.FindName($_.Name)}
#$xaml.SelectNodes("//*[@Name]") | %{Set-Variable -Name ($_.Name) -Value $Form.FindName($_.Name)}

#===========================================================================
# Create Data Module
#===========================================================================
$now=Get-Date
$viewModel = New-Object DynamicViewModel @{
Interval=1;
TotalTime=New-TimeSpan $now $now.AddHours(1);
EndTime=$now.AddHours(1);
StartTime=$now;
IdleTime=5;
DefaultIdleTime=0;
Running=New-Object TimeSpan;
Stopped=$true;
TypeKey="CountDown";
ExtraMsg="";
Display={("`n{0,-20}{1}" -f "Name","Value"); ("{0,-20}{1}" -f "----------","---------"); $viewModel.Keys |
%{"{0,-20}{1}" -f $_,(&{if(([String]$viewModel[$_]).length -ge 60) {([String]$viewModel[$_]).Substring(0,57)+"..."} else {$viewModel[$_]}})} | Sort }
}

$window.DataContext = $viewModel

#===========================================================================
$c= New-Object ConverterWrap
$c.ConvertPS={
param($value, [Type]$targetType, [Object]$parameter, [System.Globalization.CultureInfo]$culture)
if ($parameter -eq $value){
$true
}
else {
$false
}
}
$c.ConvertBackPS={
param($value, [Type]$targetType, [Object]$parameter, [System.Globalization.CultureInfo]$culture)
if ($value) {
$parameter
} else {
[System.Windows.Data.Binding]::DoNothing
}
}

$b=New-Object System.Windows.Data.Binding "TypeKey"
$b.Mode="TwoWay"
$b.Converter=$c
$b.ConverterParameter="CountDown"
$b.UpdateSourceTrigger="PropertyChanged"
$rbCountDown.SetBinding([System.Windows.Controls.RadioButton]::IsCheckedProperty, $b) | out-null

$b=New-Object System.Windows.Data.Binding "TypeKey"
$b.Mode="TwoWay"
$b.Converter=$c
$b.ConverterParameter="EndTime"
$b.UpdateSourceTrigger="PropertyChanged"
$rbEndTime.SetBinding([System.Windows.Controls.RadioButton]::IsCheckedProperty, $b) | out-null

$b=New-Object System.Windows.Data.Binding "TypeKey"
$b.Mode="TwoWay"
$b.Converter=$c
$b.ConverterParameter="IdleTime"
$b.UpdateSourceTrigger="PropertyChanged"
$rbIdleTime.SetBinding([System.Windows.Controls.RadioButton]::IsCheckedProperty, $b) | out-null

$b=New-Object System.Windows.Data.Binding "TypeKey"
$b.Mode="TwoWay"
$b.Converter=$c
$b.ConverterParameter="KeepAwake"
$b.UpdateSourceTrigger="PropertyChanged"
$rbKeepAwake.SetBinding([System.Windows.Controls.RadioButton]::IsCheckedProperty, $b) | out-null

#===========================================================================
for ($i=0; $i -lt 24; $i++) {
$cbHours.Items.Add($i) | Out-Null
}
for ($i=0; $i -lt 60; $i++) {
$cbMinutes.Items.Add($i) | Out-Null
}
for ($i=0; $i -lt 60; $i++) {
$cbSeconds.Items.Add($i) | Out-Null
}

$c= New-Object ConverterWrap
#$c.debugLevel=1
$c.ConvertPS={
param($value, [Type]$targetType, [Object]$parameter, [System.Globalization.CultureInfo]$culture)
#Write-Host "c.ConvertBackPS: " $value
if ($parameter -eq "Hours"){
$value.Hours
}
elseif ($parameter -eq "Minutes"){
$value.Minutes
}
elseif ($parameter -eq "Seconds"){
$value.Seconds
}
else {
[System.Windows.DependencyProperty]::UnsetValue
}
}
$c.ConvertBackPS={
param($value, [Type]$targetType, [Object]$parameter, [System.Globalization.CultureInfo]$culture)
try{
if ($parameter -eq "Hours"){
New-TimeSpan -Hours $value -Minutes $viewModel.TotalTime.Minutes -Seconds $viewModel.TotalTime.Seconds
}
elseif ($parameter -eq "Minutes"){
New-TimeSpan -Hours $viewModel.TotalTime.Hours -Minutes $value -Seconds $viewModel.TotalTime.Seconds
}
elseif ($parameter -eq "Seconds"){
New-TimeSpan -Hours $viewModel.TotalTime.Hours -Minutes $viewModel.TotalTime.Minutes -Seconds $value
}
else {
[System.Windows.DependencyProperty]::UnsetValue
}

}
catch {
[System.Windows.DependencyProperty]::UnsetValue
#[System.Windows.Data.Binding]::DoNothing
}
}

$b=New-Object System.Windows.Data.Binding "TotalTime"
$b.Mode="TwoWay"
$b.Converter=$c
$b.ConverterParameter="Hours"
$b.UpdateSourceTrigger="LostFocus"
$cbHours.SetBinding([System.Windows.Controls.ComboBox]::TextProperty, $b) | out-null

$b=New-Object System.Windows.Data.Binding "TotalTime"
$b.Mode="TwoWay"
$b.Converter=$c
$b.ConverterParameter="Minutes"
$b.UpdateSourceTrigger="LostFocus"
$cbMinutes.SetBinding([System.Windows.Controls.ComboBox]::TextProperty, $b) | out-null

$b=New-Object System.Windows.Data.Binding "TotalTime"
$b.Mode="TwoWay"
$b.Converter=$c
$b.ConverterParameter="Seconds"
$b.UpdateSourceTrigger="LostFocus"
$cbSeconds.SetBinding([System.Windows.Controls.ComboBox]::TextProperty, $b) | out-null

#===========================================================================
$c1= New-Object ConverterWrap
#$c1.debugLevel=1
$c1.ConvertPS={
param($value, [Type]$targetType, [Object]$parameter, [System.Globalization.CultureInfo]$culture)
"{0:MM/dd/yyyy hh:mm:ss tt}" -f $value
#([Datetime]$value).ToString("MM/dd/yyyy hh:mm:ss tt")
#$value
}
$c1.ConvertBackPS={
param($value, [Type]$targetType, [Object]$parameter, [System.Globalization.CultureInfo]$culture)
Write-Host "c1.ConvertBackPS: " $value
try{
[Datetime]$value
}
catch {
[System.Windows.DependencyProperty]::UnsetValue
#[System.Windows.Data.Binding]::DoNothing
}
}

$b=New-Object System.Windows.Data.Binding "EndTime"
$b.Mode="TwoWay"
$b.Converter=$c1
#$b.StringFormat="{0:MM/dd/yyyy hh:mm:ss tt}"
#$b.UpdateSourceTrigger="PropertyChanged"
$tbEndTime.SetBinding([System.Windows.Controls.TextBox]::TextProperty, $b) | out-null

#===========================================================================
$tick={
#Write-Host $args[0]
#Write-Host $args[1]

$now=Get-Date
switch ($viewModel.TypeKey) {
"CountDown" {
$viewModel.Running -= $timer.Interval
}
"EndTime" {
$viewModel.Running = $viewModel.EndTime - $now
}
"IdleTime" {
$viewModel.spinfo = [PowerManagerNS.PowerManager]::GetPowerInformation()
#$pbStatus.Value = [int]$viewModel.IdleTime*60 - $viewModel.DefaultIdleTime + $viewModel.spinfo.TimeRemaining
$viewModel.Running -= $timer.Interval
#            Write-Host ([int]$viewModel.IdleTime*60 - $viewModel.DefaultIdleTime + $viewModel.spinfo.TimeRemaining -
#                $viewModel.Running.Totalseconds)
if ((([int]$viewModel.IdleTime*60 - $viewModel.DefaultIdleTime + $viewModel.spinfo.TimeRemaining -
$viewModel.Running.Totalseconds) -gt 30) -and
($viewModel.spinfo.TimeRemaining -eq $viewModel.DefaultIdleTime)){
$viewModel.Running = [timespan]::FromMinutes([int]$viewModel.IdleTime)
}
}
"KeepAwake" {
$viewModel.Running = $now - $viewModel.StartTime
$viewModel.spinfo = [PowerManagerNS.PowerManager]::GetPowerInformation()
#$tbStatus.Text = "Keep Awake. Idle Time: $($viewModel.spinfo.TimeRemaining)"
[PowerManagerNS.PowerManager]::SetThreadExecutionState([PowerManagerNS.PowerManager]::ES_SYSTEM_REQUIRED)
}
}
if ($viewModel.Running.TotalSeconds -gt 0 -and  $viewModel.Running.TotalSeconds -lt $viewModel.Interval*4){
[console]::beep(500,300)
}
if (($viewModel.Running.TotalSeconds -le 0) -and ($viewModel.TypeKey -ne "KeepAwake")){
$timer.Stop();
$viewModel.stopped=$true
$btStart.Content="Start"
[console]::beep(900,900)
TimeReached
}
#UpdateStatus -now $now
}

#===========================================================================
$mc=New-Object MultiValueConverterWrap
$mc.ConvertPS={
param([Object[]]$value, [Type]$targetType, [Object]$parameter, [System.Globalization.CultureInfo]$culture)
$return = $value[0] + " - " + (&{ if($value[3]){"Stopped"} else {"Running"}}) + "`n"
switch ($value[0]) {
"CountDown" {
$end=$now + $viewModel.Running
$text = "Now: $now `nTotal " + ("{0:hh\:mm\:ss}" -f $viewModel.Running) + " to $end"
}

"EndTime" {
$s=[Int]$viewModel.Running.TotalSeconds
$text= "Now: $now `nTotal " + ("{0:hh\:mm\:ss}" -f $viewModel.Running) + " to $($viewModel.EndTime)"
}

"IdleTime" {
$ts =  [timespan]::fromseconds($viewModel.spinfo.TimeRemaining)
$end=$now + $ts
$text = "Idle: "+ ("{0:hh\:mm\:ss}" -f $ts) +"`n" +
"Remain: " + "{0:hh\:mm\:ss}" -f $viewModel.Running
}

"KeepAwake" {
$ts =  [timespan]::fromseconds($viewModel.spinfo.TimeRemaining)
$text = "Idle: "+ ("{0:hh\:mm\:ss}" -f $ts) +"`n" +
"Pass: " + "{0:hh\:mm\:ss}" -f $viewModel.Running
}
}
if ($value[3]) {
$tbStatus.Background = [System.Windows.Media.Brushes]::Transparent

} else {
if (($viewModel.Running.TotalSeconds -lt 60) -and ($viewModel.TypeKey -ne "KeepAwake")){
$tbStatus.Background = [System.Windows.Media.Brushes]::Red
}
}
$return + $text + "`n" + $value[5]

}
$mc.ConvertBackPS={
param($value, $targetType, [Object]$parameter, [System.Globalization.CultureInfo]$culture)
$null
}
$mb = New-Object System.Windows.Data.MultiBinding;
$mb.Converter = $mc;
$mb.Mode = "OneWay"

$b1=New-Object System.Windows.Data.Binding "TypeKey"
$b2=New-Object System.Windows.Data.Binding "TotalTime"
$b3=New-Object System.Windows.Data.Binding "EndTime"
$b4=New-Object System.Windows.Data.Binding "Stopped"
$b5=New-Object System.Windows.Data.Binding "Running"
$b6=New-Object System.Windows.Data.Binding "ExtraMsg"
$mb.Bindings.Add($b1);
$mb.Bindings.Add($b2);
$mb.Bindings.Add($b3);
$mb.Bindings.Add($b4);
$mb.Bindings.Add($b5);
$mb.Bindings.Add($b6);
$tbStatus.SetBinding([System.Windows.Controls.TextBox]::TextProperty, $mb) | out-null

#===========================================================================

$cbHours.add_GotFocus({
#$rbCountDown.IsChecked = $true
$viewModel.TypeKey="CountDown"
})
$cbMinutes.add_GotFocus({
#$rbCountDown.IsChecked = $true
$viewModel.TypeKey="CountDown"
})
$cbSeconds.add_GotFocus({
#$rbCountDown.IsChecked = $true
$viewModel.TypeKey="CountDown"
})

$tbEndTime.add_GotFocus({
#$rbEndTime.IsChecked = $true
$viewModel.TypeKey="EndTime"
})

$cbIdleTime.add_GotFocus({
#$rbIdleTime.IsChecked = $true
$viewModel.TypeKey="IdleTime"
})

#Timer Event
$btStart.Add_Click({
#Create Timer object
$now = Get-Date
if (-not $timer) {
#System.Windows.Forms.Timer
$Global:timer = new-object  System.Windows.Threading.DispatcherTimer
$timer.Interval = [TimeSpan]::fromseconds($viewModel.Interval) #($cbInterval.Text)
$timer.Add_Tick($tick)
}

if ($viewModel.Stopped){

switch ($viewModel.TypeKey) {
"CountDown" {
$viewModel.Running = $viewModel.TotalTime
#$pbStatus.Value = $viewModel.Running.TotalSeconds
}

"EndTime" {
$viewModel.Running = $viewModel.EndTime - $now
#$pbStatus.Value = $viewModel.Running.TotalSeconds
}

"IdleTime" {
$viewModel.StartTime = $now
$viewModel.spinfo = [PowerManagerNS.PowerManager]::GetPowerInformation()
$viewModel.DefaultIdleTime = $viewModel.spinfo.TimeRemaining
$viewModel.Running = [timespan]::FromMinutes([int]$viewModel.IdleTime)
#$pbStatus.Value = [int]$viewModel.IdleTime*60 - $viewModel.DefaultIdleTime + $viewModel.spinfo.TimeRemaining
#$tbStatus.Text = "Idle: $ts Now: $now to $end"
}

"KeepAwake" {
$viewModel.StartTime = $now
$viewModel.spinfo = [PowerManagerNS.PowerManager]::GetPowerInformation()
#$tbStatus.Text = "Keep Awake. Idle Time: $($viewModel.spinfo.TimeRemaining)"
}
}
$timer.Interval = [TimeSpan]::fromseconds($viewModel.Interval)

$pbStatus.Minimum = 0
$pbStatus.Maximum = $viewModel.Running.TotalSeconds
$viewModel.Stopped = $false;
#        if ($viewModel.Running -lt [TimeSpan]::FromSeconds(60)){
#            $tbStatus.Background = [System.Windows.Media.Brushes]::Red
#        } else {
#            $tbStatus.Background = [System.Windows.Media.Brushes]::Transparent
#        }
}

if ($timer.IsEnabled){
$timer.Stop();
$btStart.Content="Start"
#$tbStatus.Text = "Paused`n" + $tbStatus.Text
} else {
#$timer.Interval = [TimeSpan]::fromseconds($cbInterval.Text)
$timer.Start()
$btStart.Content="Pause"
}

#UpdateStatus -now $now
})

$btReset.Add_Click({
if ($timer) { $timer.Stop()};
$btStart.Content="Start"
$viewModel.Stopped=$true
$viewModel.Running = New-Object Timespan
$pbStatus.Maximum=1

})

$btNow.add_Click({
$viewModel.EndTime = (Get-Date).AddHours(1)
})

#===========================================================================

function ExecText($command) {
try{
if ($command[0] -eq '"') { iex "& $command" }
else { iex $command }
$tbCmd.Background=[System.Windows.Media.Brushes]::Transparent
$viewModel.ExtraMsg=''
} catch {
Write-Host $_
$viewModel.ExtraMsg=$_
$tbCmd.Background=[System.Windows.Media.Brushes]::Red
}
}

function TimeReached(){
#$tbStatus.Text="Time Reached!"
#Shutdown.exe -t 30 -s
ExecText $tbCmd.Text
}

$btExec.Add_Click({
#Shutdown.exe -a
ExecText $tbCmd.Text
})

#===========================================================================
$Form.ShowDialog() | Out-Null

Posted in C#, Powershell, XAML | Leave a comment

Write a GUI in Powershell – Part 6

6a. This is the last C# class. This class will call function in Kernel.dll and PowrProf.dll to get power info.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace PowerManagerNS
{

//public Guid GUID_SLEEP_SUBGROUP = new Guid("238C9FA8-0AAD-41ED-83F4-97BE242C8F20");
public static class PowerManager
{

public const uint WM_POWERBROADCAST         = 0x0218; // 536
public const uint PBT_APMQUERYSUSPEND       = 0x0000;
public const uint PBT_APMQUERYSTANDBY       = 0x0001;
public const uint PBT_APMQUERYSUSPENDFAILED = 0x0002;
public const uint PBT_APMQUERYSTANDBYFAILED = 0x0003;
public const uint PBT_APMSUSPEND            = 0x0004;
public const uint PBT_APMSTANDBY            = 0x0005;
public const uint PBT_APMRESUMECRITICAL     = 0x0006;
public const uint PBT_APMRESUMESUSPEND      = 0x0007;
public const uint PBT_APMRESUMESTANDBY      = 0x0008;
public const uint PBT_APMBATTERYLOW         = 0x0009;
public const uint PBT_APMPOWERSTATUSCHANGE  = 0x000A;
public const uint PBT_APMOEMEVENT           = 0x000B;
public const uint PBT_APMRESUMEAUTOMATIC    = 0x0012;
public const uint PBTF_APMRESUMEFROMFAILURE = 0x00000001;
public const uint ES_DISPLAY_REQUIRED       = 0x00000002; // zero the display''s idle timer
public const uint ES_SYSTEM_REQUIRED        = 0x00000001; // zero the system''s idle timer
public const uint ES_CONTINUOUS             = 0x80000000; // keep the display or system on (doesn''t work?)
public const uint BROADCAST_QUERY_DENY      = 0x424D5144;

public const int SystemPowerInformation = 12;
public const uint STATUS_SUCCESS = 0;

public static Guid GUID_SLEEP_SUBGROUP = new Guid("238C9FA8-0AAD-41ED-83F4-97BE242C8F20");

[StructLayout(LayoutKind.Sequential)]
public struct SYSTEM_POWER_INFORMATION
{
public uint MaxIdlenessAllowed;
public uint Idleness;
public uint TimeRemaining;
public Byte CoolingMode;
}

public static long size
{
get
{
return System.Runtime.InteropServices.Marshal.SizeOf(typeof(SYSTEM_POWER_INFORMATION));
}
}

[DllImport("PowrProf.dll", CharSet = CharSet.Auto,SetLastError = true)]
public static extern uint CallNtPowerInformation(int InformationLevel, IntPtr lpInputBuffer, long nInputBufferSize,
IntPtr lpOutputBuffer, long nOutputBufferSize);

[DllImport("PowrProf.dll", CharSet = CharSet.Auto,SetLastError = true)]
public static extern uint CallNtPowerInformation(int InformationLevel, IntPtr lpInputBuffer, long nInputBufferSize,
out SYSTEM_POWER_INFORMATION lpOutputBuffer, long nOutputBufferSize);

[DllImport("kernel32.dll", CharSet = CharSet.Auto,SetLastError = true)]
public static extern void SetThreadExecutionState(uint esFlags);

[DllImport("PowrProf.dll", CharSet = CharSet.Auto,SetLastError = true)]
public static extern Int32 PowerReadValueMax(
IntPtr RootPowerKey,
ref Guid SubGroupOfPowerSettingsGuid,
ref Guid PowerSettingGuid,
ref Int32 ValueMaximum
);

public static SYSTEM_POWER_INFORMATION GetPowerInformation1()
{
SYSTEM_POWER_INFORMATION spinfo = new SYSTEM_POWER_INFORMATION();
IntPtr pointer = Marshal.AllocHGlobal(Marshal.SizeOf(spinfo));
Marshal.StructureToPtr(spinfo, pointer, true);
CallNtPowerInformation(SystemPowerInformation, (IntPtr)0, 0, pointer, size);
spinfo = (SYSTEM_POWER_INFORMATION)Marshal.PtrToStructure(pointer, typeof(SYSTEM_POWER_INFORMATION));

return spinfo;
}

public static SYSTEM_POWER_INFORMATION GetPowerInformation()
{
SYSTEM_POWER_INFORMATION spinfo;
uint retval = CallNtPowerInformation(SystemPowerInformation, (IntPtr)0, 0, out spinfo, Marshal.SizeOf(typeof(SYSTEM_POWER_INFORMATION)));
if (retval == STATUS_SUCCESS)
return spinfo;
else
{
Console.WriteLine("Error: " + retval);
return new SYSTEM_POWER_INFORMATION();
}
}

public static Int32 GetPowerReadValueMax()
{
Int32 value=0;
Guid g = new Guid("238C9FA8-0AAD-41ED-83F4-97BE242C8F20");
Guid g2 = Guid.Empty;
Int32 retval = PowerReadValueMax((IntPtr)null, ref GUID_SLEEP_SUBGROUP, ref g2, ref value);
if (retval == STATUS_SUCCESS)
return value;
else
return retval;

}
}
}

6b. Add to Powershell

$code=Get-Content -Raw -Path (Join-Path $path "PowerManagerNS.cs")
Add-Type -TypeDefinition $code

Posted in C#, Powershell, XAML | Leave a comment

Write a GUI in Powershell – Part 5

5a. Create an other C# class

using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows.Data;
using System.Management.Automation;
public class MultiValueConverterWrap : IMultiValueConverter
{
public Func<object[], Type, object, CultureInfo, PSObject> ConvertPS;
public Func<object, Type[], object, CultureInfo, PSObject> ConvertBackPS;
public int debugLevel = 0;

public object Convert(object[] value, Type targetType, object parameter, CultureInfo culture)
{
try
{
DebugPrint("ConverterWrap: Convert: ");
PSObject p = ConvertPS(value, targetType, parameter, culture);
if (p == null)
{
DebugPrint("ConverterWrap: ConvertBack: null");
return null;
}
else
{
//Object o = p.ImmediateBaseObject;
Object o = p.BaseObject;
//Type t = o.GetType;
return o;
}
}
catch (Exception e)
{
DebugPrint(e.Message);
return System.Windows.DependencyProperty.UnsetValue;
}
}

public object[] ConvertBack(object value, Type[] targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
DebugPrint("ConverterWrap: ConvertBack: ");
PSObject p = ConvertBackPS(value, targetType, parameter, culture);
DebugPrint("ConverterWrap: ConvertBack: " + p + "\t" + p.GetType());
//Object o = p.ImmediateBaseObject;
Object[] o = (Object[])p.BaseObject;
return o;
}
catch (Exception e)
{
DebugPrint(e.Message);
return null; //System.Windows.DependencyProperty.UnsetValue;
}
}

protected void DebugPrint(String s)
{
if (debugLevel == 1)
{
Console.WriteLine(s);
}
}
}

5b. add to Powershell
$csharp3=Get-Content (Join-Path $path "MultiValueConverterWrap.cs") -Raw
Add-Type -TypeDefinition $csharp3 -ReferencedAssemblies @("PresentationFramework";"WindowsBase")

Posted in C#, Powershell, XAML | Leave a comment

Write a GUI in Powershell – Part 4

4a. Create converter in C# for data binding for the same reason, Powershell doesn’t support C# interface.

using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows.Data;
using System.Management.Automation;

public class ConverterWrap : IValueConverter
{
public Func<object, Type, object, CultureInfo, PSObject> ConvertPS;
public Func<object, Type, object, CultureInfo, PSObject> ConvertBackPS;
public int debugLevel = 0;

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
DebugPrint("ConverterWrap: Convert: ");
PSObject p = ConvertPS(value, targetType, parameter, culture);
if (p == null)
{
DebugPrint("ConverterWrap: ConvertBack: null");
return null;
}
else
{
//Object o = p.ImmediateBaseObject;
Object o = p.BaseObject;
return o;
}
}
catch (Exception e)
{
DebugPrint(e.Message);
return System.Windows.DependencyProperty.UnsetValue;
}
}

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
DebugPrint("ConverterWrap: ConvertBack: ");
PSObject p = ConvertBackPS(value, targetType, parameter, culture);
if (p == null)
{
DebugPrint("ConverterWrap: ConvertBack: null");
return null;
}
else
{
DebugPrint("ConverterWrap: ConvertBack: " + p + "\t" + p.GetType());
//Object o = p.ImmediateBaseObject;
Object o = p.BaseObject;
//DebugPrint("ConverterWrap: ConvertBack: " + o + "\t" + o.GetType());
return o;
}
}
catch (Exception e)
{
DebugPrint(e.Message);
return System.Windows.DependencyProperty.UnsetValue;
}

}

protected void DebugPrint(String s)
{
if (debugLevel == 1)
{
Console.WriteLine(s);
}
}
}

4b. Add it to Powershell

$csharp2=Get-Content (Join-Path $path "ConverterWrap.cs") -Raw
Add-Type -TypeDefinition $csharp2 -ReferencedAssemblies @("PresentationFramework";"WindowsBase")

Posted in C#, Powershell, XAML | Leave a comment

Write a GUI in Powershell – Part 3

3a. Create data module in C#, This is useful when doing data binding. Don’t know if Powershell is able to create a custom object inherit a C# interface. But Powershell can use Add-Type to add a C# class. Then we just create a simple C# class, and add it to Powershell.

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Dynamic;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.ComponentModel;
using System.Management.Automation;

public class DynamicViewModel : DynamicObject, INotifyPropertyChanged
{
private Hashtable properties;
public event PropertyChangedEventHandler PropertyChanged;
public int debugLevel=0;

public DynamicViewModel()
{
this.properties = new Hashtable();
}

public DynamicViewModel(Hashtable data)
{
this.properties = data;
}

public int Count
{
get
{
return properties.Count;
}
}

public System.Collections.ICollection Keys
{
get
{
return properties.Keys;
}
}

public System.Collections.ICollection Values
{
get
{
return properties.Values;
}
}

// If you try to get a value of a property
// not defined in the class, this method is called.
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
DebugPrint("Get: " + binder.Name + " = " +  " | " + binder.Name.GetType());
result = properties.ContainsKey(binder.Name) ? properties[binder.Name] : null;
return true;
}

// If you try to set a value of a property that is
// not defined in the class, this method is called.
public override bool TrySetMember(SetMemberBinder binder, object value)
{
DebugPrint("TrySetMember: " + binder.Name + " = " + value + " | " + binder.Name.GetType() + " = " + value.GetType());
properties[binder.Name] = value;
RaisePropertyChanged(binder.Name);
return true;
}

// Get the property value by index.
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{
DebugPrint("TryGetIndex: " + indexes[0] + " = " + " | " + indexes[0].GetType());
result = properties.ContainsKey(indexes[0].ToString()) ? properties[indexes[0].ToString()] : null;
return true;
}

// Set the property value by index.
public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
{
try
{
DebugPrint("TrySetIndex: " + indexes[0] + " = " + value + " | " + indexes[0].GetType() + " = " + value.GetType());
//properties[indexes[0].ToString()] = value;
properties[(String)indexes[0]] = value;
RaisePropertyChanged((String)indexes[0]);
return true;
}
catch (Exception e)
{
DebugPrint("TrySetIndex Exception: " + e);
return false;
}

}

public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
DebugPrint("TryInvokeMember: ");
try
{
if (properties.ContainsKey(binder.Name))
{
DebugPrint("TryInvokeMember Key Found: " + binder.Name + " | " + properties[binder.Name].GetType());
result = ((ScriptBlock)properties[binder.Name]).InvokeReturnAsIs(args);
//result = ((Func<object[], object>)properties[binder.Name]).Invoke(args);
DebugPrint("TryInvokeMember Key Found - result: " + result);
}
else
{
DebugPrint("TryInvokeMember Key Not Found: " + binder.Name);
result = null;
return false;
}
return true;
}
catch (Exception e)
{
DebugPrint("TryInvokeMember Exception: " + e);
result = null;
return false;
}
}

// Converting an object to a specified type.
public override bool TryConvert(ConvertBinder binder, out object result)
{
// Converting to string.
if (binder.Type == typeof(String))
{
result = "DynamicViewModel with " +
((properties.Count > 1) ? ("" + properties.Count + " Dynamic Properties") :
("" + properties.Count + " Dynamic Property"));
return true;
}

// In case of any other type, the binder
// attempts to perform the conversion itself.
// In most cases, a run-time exception is thrown.
return base.TryConvert(binder, out result);
}

public override IEnumerable<String> GetDynamicMemberNames()
{
return properties.Keys.Cast<String>() ;
}

public override string ToString()
{
return "DynamicViewModel with " +
((properties.Count > 1) ? ("" + properties.Count + " Dynamic Properties") :
("" + properties.Count + " Dynamic Property"));
}

public bool Remove(string name)
{
if (properties.ContainsKey(name))
{
properties.Remove(name);
return true;
}
else
{
return false;
}
}

public void Print()
{
foreach (DictionaryEntry pair in properties)
{
if (pair.Value != null)
{
Console.WriteLine(pair.Key + " \t" + pair.Value + " \t" + pair.Value.GetType());
}
else
{
Console.WriteLine(pair.Key + " \t" + pair.Value + " \tNull Value");
}

}

if (properties.Count == 0)
Console.WriteLine("No elements in the dictionary.");
}

protected void RaisePropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}

protected void DebugPrint(String s)
{
if (debugLevel == 1)
{
Console.WriteLine(s);
}
}
}

3b. Add DynamicViewModel.cs to Powershell

$csharp1=Get-Content (Join-Path $path "DynamicViewModel.cs") -Raw
Add-Type -TypeDefinition $csharp1

Posted in Uncategorized | Leave a comment

Write a GUI in Powershell – Part 2

2. Convert XAML to powershell

[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$xaml = Get-Content -Raw -Path (Join-Path $path "autoshutdown.xaml")

#Read XAML
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
catch{Write-Host "Unable to load Windows.Markup.XamlReader. Some possible causes for this problem include: .NET Framework is missing PowerShell must be launched with PowerShell -sta, invalid XAML code was encountered."; exit}

$manager = New-Object System.Xml.XmlNamespaceManager $xaml.NameTable;
$manager.AddNamespace("xaml", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
$manager.AddNamespace("x", "http://schemas.microsoft.com/winfx/2006/xaml");
$xaml.SelectNodes("//*[@x:Name]", $manager ) | %{Set-Variable -Name ($_.Name) -Value $Form.FindName($_.Name)}

Posted in C#, Powershell, XAML | Leave a comment

Write a GUI in Powershell – Part 1

1. Create XAML interface in Visual Studio.  This will be fast and less coding.  Delete x:class property in Window tag and save the file.

Codes:


<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Collections="clr-namespace:System.Collections;assembly=mscorlib"
x:Name="window" Title="Shutdown PC" Height="436.098" Width="544">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="298*"/>
<RowDefinition Height="107*"/>
</Grid.RowDefinitions>
<Grid IsEnabled="{Binding Stopped}" Margin="0,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="46*"/>
<RowDefinition Height="34*"/>
<RowDefinition Height="34*"/>
<RowDefinition Height="29*"/>
<RowDefinition Height="37*"/>
<RowDefinition Height="79*"/>
<RowDefinition Height="39*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="102*"/>
<ColumnDefinition Width="135*"/>
<ColumnDefinition Width="113*"/>
<ColumnDefinition Width="36*"/>
<ColumnDefinition Width="148*"/>
</Grid.ColumnDefinitions>
<RadioButton x:Name="rbCountDown" Content="Count Down" HorizontalAlignment="Left" Margin="10,25,0,0" VerticalAlignment="Top" Height="15" Width="85" GroupName="Type" IsChecked="True"/>
<RadioButton x:Name="rbEndTime" Content="End Time" HorizontalAlignment="Left" Margin="10,12,0,0" VerticalAlignment="Top" Height="15" Width="85" GroupName="Type" Grid.Row="1"/>
<RadioButton x:Name="rbIdleTime" Content="Idle Time" HorizontalAlignment="Left" Margin="10,10,0,0" Grid.Row="2" VerticalAlignment="Top" Height="15" Width="68" GroupName="Type"/>
<RadioButton x:Name="rbKeepAwake" Content="Keep Awake" HorizontalAlignment="Left" Margin="10,9,0,0" Grid.Row="3" VerticalAlignment="Top" Height="15" Width="84" GroupName="Type"/>
<Label Content="Hours" Grid.Column="1" HorizontalAlignment="Left" Margin="10,-5,0,0" VerticalAlignment="Top" Width="78" Height="26"/>
<Label Content="Minutes" Grid.Column="2" HorizontalAlignment="Left" Margin="10,-5,0,0" VerticalAlignment="Top" Height="26" Width="74"/>
<Label Content="Seconds" Grid.Column="4" HorizontalAlignment="Left" Margin="10,-5,0,0" VerticalAlignment="Top" Height="26" Width="93"/>
<ComboBox x:Name="cbHours" Grid.Column="1" Margin="10,21,10,0" Height="22" VerticalAlignment="Top" IsEditable="True" SelectedIndex="0"/>
<ComboBox x:Name="cbMinutes" Grid.Column="2" Margin="10,21,10,0" Height="22" VerticalAlignment="Top" IsEditable="True" SelectedIndex="1" Grid.ColumnSpan="2"/>
<ComboBox x:Name="cbSeconds" Grid.Column="4" Margin="10,21,10,0" Height="22" VerticalAlignment="Top" IsEditable="True" SelectedIndex="0"/>
<Label Content="To:" Grid.Column="1" HorizontalAlignment="Left" Margin="8,6,0,0" Grid.Row="1" VerticalAlignment="Top" Width="55" Height="26"/>
<TextBox x:Name="tbEndTime" Grid.Column="1" Margin="45,8,11,0" Grid.Row="1" VerticalAlignment="Top" Height="22" Grid.ColumnSpan="2" />
<Button x:Name="btNow" Content="Now+1hr" Grid.Column="3" HorizontalAlignment="Left" Margin="9,9,0,0" Grid.Row="1" VerticalAlignment="Top" Width="75" Height="20" Grid.ColumnSpan="2"/>
<ComboBox x:Name="cbIdleTime" Grid.Column="1" Margin="10,8,0,0" Grid.Row="2" VerticalAlignment="Top" Height="22"  IsEditable="True" Text="{Binding IdleTime}">
<ComboBoxItem Content="15"/>
<ComboBoxItem Content="20"/>
<ComboBoxItem Content="25"/>
<ComboBoxItem Content="30"/>
<ComboBoxItem Content="45"/>
<ComboBoxItem Content="60"/>
<ComboBoxItem Content="120"/>
</ComboBox>
<Label Content="Interval" VerticalAlignment="Top" Margin="12,3,0,0" Grid.Row="4" Height="26" HorizontalAlignment="Left" Width="80"/>
<ComboBox x:Name="cbInterval" Text="{Binding DataContext[Interval], Mode=TwoWay, RelativeSource={RelativeSource Self}}" Grid.Column="1" Margin="10,7,102,0" Grid.Row="4" VerticalAlignment="Top" Height="22" IsEditable="True" SelectedIndex="0" Grid.ColumnSpan="2" >
<ComboBoxItem Content="1" />
<ComboBoxItem Content="2" />
<ComboBoxItem Content="3" />
<ComboBoxItem Content="4" />
<ComboBoxItem Content="5" />
</ComboBox>
<TextBox x:Name="tbStatus" Grid.ColumnSpan="5" Margin="22,10,23,3" VerticalScrollBarVisibility="Visible" Grid.Row="5" TextWrapping="Wrap" IsReadOnly="True" IsReadOnlyCaretVisible="True"/>
<ProgressBar x:Name="pbStatus" Value="{Binding Running.TotalSeconds, Mode=OneWay}" Minimum="0" FlowDirection="RightToLeft" Margin="22,9,23,0" Grid.Row="6" Grid.ColumnSpan="5" Height="21" VerticalAlignment="Top">
<ProgressBar.Foreground>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<LinearGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterY="0.5" CenterX="0.5"/>
<SkewTransform CenterY="0.5" CenterX="0.5"/>
<RotateTransform Angle="90" CenterY="0.5" CenterX="0.5"/>
<TranslateTransform/>
</TransformGroup>
</LinearGradientBrush.RelativeTransform>
<GradientStop Color="Yellow" Offset="1"/>
<GradientStop Color="Lime"/>
</LinearGradientBrush>
</ProgressBar.Foreground>
</ProgressBar>
<TextBox x:Name="cbRunning" Grid.Column="1" Margin="17,9,10,0" Grid.Row="6" Grid.ColumnSpan="3" Text="{Binding Running, StringFormat=hh\\:mm\\:ss}" IsEnabled="False" TextAlignment="Center" BorderThickness="0" Background="{x:Null}" Foreground="#FFFF0000" FontWeight="Bold" Height="22" VerticalAlignment="Top"/>
<Label Content="Minutes" Grid.Column="2" Margin="11,6,0,0" Grid.Row="2" Height="26" VerticalAlignment="Top" HorizontalAlignment="Left" Width="53"/>
<Label Content="Seconds" Grid.Column="2" HorizontalAlignment="Right" Margin="0,5,39,0" Grid.Row="4" VerticalAlignment="Top" RenderTransformOrigin="0.974,-0.808"/>
</Grid>
<Grid Margin="0,0" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="16*"/>
<RowDefinition Height="91*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="21*"/>
<ColumnDefinition Width="86*"/>
<ColumnDefinition Width="221*"/>
<ColumnDefinition Width="208*"/>
</Grid.ColumnDefinitions>
<Label Content="Command to be executed when time is reached" HorizontalAlignment="Left" Margin="0,-6,0,0" VerticalAlignment="Top" Grid.ColumnSpan="3" Width="491" Height="26" Grid.RowSpan="2" Grid.Column="1"/>
<TextBox x:Name="tbCmd" Margin="0,3,23,35" TextWrapping="Wrap" AcceptsReturn="True"  VerticalScrollBarVisibility="Visible" IsEnabled="True" Grid.ColumnSpan="3" Grid.Row="1" SpellCheck.IsEnabled="True" Grid.Column="1" Text="{Binding Text, ElementName=cbCmds, Mode=OneWay}"/>
<Button x:Name="btExec" Content="Exec" Margin="0,0,0,10" Height="20" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="75" Grid.Column="1" Grid.Row="1"/>
<ComboBox x:Name="cbCmds" SelectedIndex="0" Grid.Column="2" Margin="10,0,10,10" Grid.Row="1" VerticalAlignment="Bottom">
<ComboBoxItem Content="Write-Host ($viewModel.Display() -join &quot;`n&quot;)" />
<ComboBoxItem Content="Shutdown -t 30 -s" />
<ComboBoxItem Content="Shutdown -a"/>
</ComboBox>
<Button x:Name="btReset" Content="Reset" Grid.Column="3" HorizontalAlignment="Left" Margin="10,0,0,10" Width="75" Height="20" VerticalAlignment="Bottom" Grid.Row="1"/>
<Button x:Name="btStart" Content="Start" Margin="0,0,40,10" Height="20" VerticalAlignment="Bottom" HorizontalAlignment="Right" Width="75" Grid.Column="3" Grid.Row="1"/>
</Grid>
</Grid>
</Window>

 

Posted in C#, Powershell, XAML | Leave a comment