PowerShell + WPF + XAML = Cool

To create a GUI for your script try using WPF + XAML.

Here is a few things that worked for me.

Lets start with a basic script.

 1: Add-Type -AssemblyName presentationframework
 2:
 3: [xml]$XAML = @"
 4: <Window
 5:   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 6:   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 7:   Height="150" Width="150">
 8:
 9: </Window>
 10: "@
 11:
 12: $Reader=(New-Object System.Xml.XmlNodeReader $xaml)
 13: $Window=[Windows.Markup.XamlReader]::Load( $Reader )
 14:
 15:
 16: $Window.ShowDialog() | out-null

That should make a small blank window appear.

image

So what you may be thinking! what good is that?

But be patient please this is only the beginning.

Lets make some text appear in the window.

 1: Add-Type -AssemblyName presentationframework
 2:
 3: [xml]$XAML = @"
 4: <Window
 5:   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 6:   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 7:   Height="150" Width="150">
 8:
 9:     <Label Content="Hello World!"/>
 10:
 11: </Window>
 12: "@
 13:
 14: $Reader=(New-Object System.Xml.XmlNodeReader $xaml)
 15: $Window=[Windows.Markup.XamlReader]::Load( $Reader )
 16:
 17:
 18: $Window.ShowDialog() | out-null

So guess what might happen?

image

So have I got your attention yet?

Ok it’s still not that exciting but hopefully you are following along.

To make it a tiny bit better to look at lets center the label in the window.and add a bit of colour.

 1: Add-Type -AssemblyName presentationframework
 2:
 3: [xml]$XAML = @"
 4: <Window
 5:   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 6:   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 7:   Height="150" Width="150"
 8:   Background="lightblue">
 9:
 10:    <Label HorizontalAlignment="Center"
 11:           VerticalAlignment="Center"
 12:           FontSize="18"
 13:           Foreground="White"
 14:           Content="Hello World!"/>
 15:
 16: </Window>
 17: "@
 18:
 19: $reader=(New-Object System.Xml.XmlNodeReader $xaml)
 20: $Window=[Windows.Markup.XamlReader]::Load( $reader )
 21:
 22: $Window.ShowDialog() | out-null

image

Now that we have it looking a bit better lets change the content of our label via PowerShell.

To be able to change the content of the label we have to do three things:

Give the label a name, find the label in the xaml and then set the content to the new value.

 1: Add-Type -AssemblyName presentationframework
 2:
 3: [xml]$XAML = @"
 4: <Window
 5:   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 6:   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 7:   Height="150" Width="150"
 8:   Background="lightblue">
 9:
 10:    <Label HorizontalAlignment="Center"
 11:           VerticalAlignment="Center"
 12:           FontSize="18"
 13:           Foreground="White"
 14:           Content="Hello World!"
 15:           Name="myHostName" />
 16:
 17: </Window>
 18: "@
 19:
 20: $reader=(New-Object System.Xml.XmlNodeReader $xaml)
 21: $Window=[Windows.Markup.XamlReader]::Load( $reader )
 22:
 23: $myHostName = $Window.findname("myHostName")
 24:
 25: $myHostName.Content = $env:computername
 26:
 27: $Window.ShowDialog() | out-null

image

The change to the script will display you computer name in the window.

 

This has been a very basic intro but it should be enough to get you going.

Tagged , , ,

Search an XML Document for a Specific Value

Here is an example of how to search through an XML document for a value of an attribute:

Here is the XML file:

<?xml version="1.0" encoding="utf-8"?>
<root>
 <archive Name="20100821">
 <File Name="Log20100821.log" SizeKB="117727" LastWriteTime="08/21/2010 06:33:35" />
 <File Name="Archive20100821.log" SizeKB="3" LastWriteTime="08/21/2010 06:33:35" />
 <File Name="Routine20100821.log" SizeKB="74" LastWriteTime="08/21/2010 06:33:36" />
 </archive>
 <archive Name="20100828">
 <File Name="Log20100828.log" SizeKB="148740" LastWriteTime="08/28/2010 06:34:14" />
 <File Name="Archive20100828.log" SizeKB="4" LastWriteTime="08/28/2010 06:34:15" />
 <File Name="Routine20100828.log" SizeKB="90" LastWriteTime="08/28/2010 06:34:15" />
 </archive>
</root>

To find <archive Name=”20100828″> try this:

$xml = [xml](get-content xml.xml)
$searchItem = "20100828"
$xml.SelectNodes("root/archive") | ? { $_.Name -eq $searchItem} | % {$_.File } | ft -AutoSize

This should return these results:

Tagged ,

How to initiate a Remote Desktop Session from Powershell

To initiate a RDP session from a script try this:

Create a new RDP Connection

Enter all the required details and then save the connection

Then you can run it from you script using this:


$RDPServer = "c:\RDP\Server1.rdp"
Write-Verbose " Invokeing $RDPServer Session"
invoke-Expression "mstsc.exe '$RDPServer'"

If you want your script to wait for the RDP session to exit before it continues then add this:

$mstscProcess = (Get-Process | Where-Object { $_.ProcessName -ieq "mstsc" })
Write-verbose "Waiting for MSTSC.EXE to exit"
$mstscProcess.WaitForExit()
Write-verbose "MSTSC.EXE ended"

Get a test page from your printers

Here is a little function to request a test page from each of the printers you are connected to.

# Get Printer Objects for this computer from WMI

$vPrinters = Get-WmiObject -Class Win32_printer

# Print a test page for each printer

foreach ($vPrinter in $vPrinters)

{ $vPrinter.PrintTestPage() }

CREATE NEW XML FILE

Here is a little function i created to create an XML file from the structure of a folder.

The folder structure looks like this:

E:\Archives\LatestArchiveFiles

20100821

Log20100821.log
Archive20100821.log
Routine20100821.log

20100828

Log20100828.log
Archive20100828.log
Routine20100828.log

It works by doing a Get-ChildItem on the folder and creating the XML file based on the folder structure.


Function New-XMLFile ($Path = "E:\Gateway\Archives")
 {
Set-Location $path
Write-Verbose "Path has been set to $path"
$VerbosePreference = "Continue"
#$VerbosePreference = "silentlyContinue"
Write-Verbose $pwd
$xml = New-Object xml
$rootElements = gci
$root = $xml.CreateElement("root")
[void]$xml.AppendChild($root)

foreach($archiveElement in $rootElements ){
 Write-Verbose "Archive Loop, for $archiveElement "
 Write-Verbose "Setting location to $archiveElement"
 set-location $path\$archiveElement
 Write-Verbose "location Set to $pwd"
 $archive = $xml.CreateElement("archive")
 [void]$root.AppendChild($archive)
 $archive.SetAttribute("Name", $archiveElement)
 $fileElements = gci
 foreach ($fileElement in $fileElements){
 Write-Verbose "File Loop"
 Write-Verbose "Looking at $fileElement`n"
 $fileSize = ($fileElement.Length/1KB).tostring("0")
 $file = $xml.CreateElement("File")
 [void]$archive.AppendChild($file)
 $file.SetAttribute("Name", $fileElement)
 $file.SetAttribute("SizeKB", $fileSize )
 $file.SetAttribute("LastWriteTime", $fileElement.LastWriteTime)
 }
 }
$xml.save("E:\Gateway\Archives")
}

New-XMLfile "C:\Documents and Settings\psuser"

The XML File created would look like this

<root>
 <archive Name="20100821">
 <File Name="Log20100821.log" SizeKB="117727" LastWriteTime="08/21/2010 06:33:35" />
 <File Name="Archive20100821.log" SizeKB="3" LastWriteTime="08/21/2010 06:33:35" />
 <File Name="Routine20100821.log" SizeKB="74" LastWriteTime="08/21/2010 06:33:36" />
 </archive>
 <archive Name="20100828">
 <File Name="Log20100828.log" SizeKB="148740" LastWriteTime="08/28/2010 06:34:14" />
 <File Name="Archive20100828.log" SizeKB="4" LastWriteTime="08/28/2010 06:34:15" />
 <File Name="Routine20100828.log" SizeKB="90" LastWriteTime="08/28/2010 06:34:15" />
 </archive>
</root>


Tagged , ,

create new folder structure

Here is a little function to create a new folder structure from a bunch of files.

The folder structure looks like this:

E:\Archives\LatestArchiveFiles

Log20100821.log
Archive20100821.log
Routine20100821.log
Log20100828.log
Archive20100828.log
Routine20100828.log

After running the function the folder structure looks like this:

E:\Archives\LatestArchiveFiles

20100821

Log20100821.log
Archive20100821.log
Routine20100821.log

20100828

Log20100828.log
Archive20100828.log
Routine20100828.log

It works by doing a Get-ChildItem on the folder and grouping the files by the date part of the file name, then it creates new folders based on the group name and moves the relevant files in to the new folder.

Function Create-New-Folder-Structure{
param($path = 'E:\Archives\LatestArchiveFiles')
$VerbosePreference = "Continue"
$ArchivePath = $null
Set-Location $path

$GroupByDate = {$z =($_.name).ToString(); $z.Substring($z.Length – 12, 8)}

$archiveGroups = Get-ChildItem '*.log' | Group-Object $GroupByDate | select group,name
write-verbose "The current folder is $pwd"
write-verbose "Start of Date Group Processing`n"

foreach ($archiveGroup in $archiveGroups){
 Set-Location $path
 $thisName = $archiveGroup.name
 write-verbose "Create new sub folder for archive $thisName"
 New-Item -Name $thisName -itemType directory
 # Copy logs to relevant year folder
 Write-Verbose "Moving archive files $thisName to $pwd\$thisName"
 $archiveGroup | % {$_.Group | % {move-item $_ -destination ($archiveGroup.name)}}
 }

Write-Verbose "$ArchivePath = $pwd"
#$global:ArchivePath = $pwd.path
Write-Verbose "$global:ArchivePath = $pwd"
return $ArchivePath
}

Create-New-Folder-Structure E:\Archives\LatestArchiveFiles

Write-Verbose $ArchivePath

Tagged ,
Follow

Get every new post delivered to your Inbox.