Montag, 28. Dezember 2009

Compare-Object & get-wmiobject win32_process does it right

Hello
the fasted way to have lots of processes with the same ProcessName is use Chrome, which opens for each tab its own process and uses a few of it's own. I heard rumours that firefox will use seperate processes in future versions too. But here I'm not going to start any process vs. thread discussion. Here I will play with processes with the same name. You can just start Notepad for this purpose.

get-process | ? {$_.Name -eq 'Notepad' } | Kill            


Notepad
Notepad
notepad
notepad

$gp_a = get-process notepad
$gwmip_a = get-wmiobject win32_process | ? {$_.Name -eq 'notepad.exe'}


The code above just ensures, that there are 4 instances of notepad running.
Next close one of the first 3 instances and take fresh snapshots.

$gp_b = get-process notepad             
$gwmip_b = get-wmiobject win32_process | ? {$_.Name -eq 'notepad.exe'}


Let's look at them:

$gp_a            


Initially there where 4 processes:


PS C:\Var\bin> $gp_a

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
69 3 992 7612 72 1492 notepad
69 3 976 4220 55 2272 notepad
68 3 972 4096 55 3368 notepad
13 1 284 60 2 5480 notepad



$gp_b


In second snapshot there are 3 processes (PID 2272 got killed)


PS C:\Var\bin> $gp_b

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
72 3 1012 7852 59 1492 notepad
72 3 1012 7800 59 3368 notepad
72 3 1020 7960 59 5480 notepad



Compare-Object $gp_a $gp_b |             
Where-object {$_.SideIndicator -ne '=='} |
Select -ExpandProperty InputObject


Trying to use Compare-Object on the results of get-Process, as recommended in http://technet.microsoft.com/en-us/library/ee156812.aspx I get a wrong result


PS C:\Var\bin> Compare-Object $gp_a $gp_b |
Where-object {$_.SideIndicator -ne '=='} |
Select -ExpandProperty InputObject


Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
13 1 284 60 2 5480 notepad



(Compare-Object $gwmip_a $gwmip_b |             
Where-object {$_.SideIndicator -ne '=='}).Inputobject |
Select ProcessId, Name


while good old WMI gives the correct answer


PS C:\Var\bin> (Compare-Object $gwmip_a $gwmip_b |
Where-object {$_.SideIndicator -ne '=='}).Inputobject |
Select ProcessId, Name


ProcessId Name
--------- ----
2272 notepad.exe




The documentation of Compare-Object contains the funny sentense:
The result of the comparison indicates whether a property value appeared only in the object from the Reference set (indic
ated by the <= symbol), only in the object from the Difference set (indicated by the => symbol) or, if the IncludeEqual p
arameter is specified, in both objects (indicated by the == symbol).


Does it chose a property by incident and in the case of Get-Process, does it use ProcessName instead of Id ?


Is there someone who can tell more about the logic Compare-Object uses to determine whether two objects are the same.

Sonntag, 27. Dezember 2009

Small Get-Process Puzzle

Hello PowerShell folks,

here I have a small puzzle for you. Please start only one instance of PowerShell odr PowerShell_ISE and run the following script.

$p1 = get-process powershell*             
$p2 = get-process powershell*

$p1
$p2

$p1 -eq $p2

Compare-Object $p1 $p2 -IncludeEqual


This time I'm not confuesed, that Compare-Object tells that both processes are equal. This time I wonder why $p1 is not equal To $p2.

When you invoke $p1 a number of times, you will see that the value CPU(s) increases. My natural expectation here is same PID same process.

Is this a PowerShell or a .NET issue ?
Do I better keep using WMI?

I get the rather strange feeling 'The more I learn, the less I know'.

Bernd

Freitag, 25. Dezember 2009

Compare-Object works different

Sorry Mr. Snover. I don't grock the way Compare-Object is intented to work.

Or I'm just misinterpreting the examples in http://technet.microsoft.com/en-us/library/ee156812.aspx for a second time.

The first time I was led to think, that Compare-Object is a good basis to produce diffs of text files. It hardly is capable to tell whether they are equal or different.

This time I thought it adequat to determine the processes which where started between two calls of GET-Process.
Well it correctly tells the name of the processes involved, but having a lot of chrome processes
(Chrome Plus to be precise) I do not get the PID of correct chrome process stopped.
And for me a process is it primary it's PID and not it's name.

With a little work around I get Compare-Object to work here as expected.


function Get-ProcessProperty ( )            
{
[CmdletBinding()]
PARAM(
$process = '*',
$timestamp = "{0:T}" -f (Get-Date)
)

$hash1 = @{}
Get-Process -Name $process | % {
$hash2 = @{}
#$hash2['Time'] = $timestamp
$hash2['Name'] = $_.name
#$hash2['CPU'] = $_.CPU
#$hash2['PM'] = "{0,3:f0}" -f ( $_.PM / 1MB )
#$hash2['NPM'] = "{0,4:f1}" -f ( $_.NPM / 1KB )
#... add further properties above
$hash1[($_.Id)] = $hash2
}
$hash1
}


$psold = get-ProcessProperty

(
'\PhysicalDisk(_total)\Current Disk Queue Length',
'\PhysicalDisk(_total)\Disk Transfers/sec'
) | Get-Counter -cont -sample 1 |% {
$timestamp = "{0:T}" -f $_.Timestamp

$diskQueue = ($_.CounterSamples[0]).CookedValue
$transfer = ($_.CounterSamples[1]).CookedValue

$msg = "{0} {1,4:f0} {2,4:f0}" -f $timestamp, $diskQueue, $transfer

$psnew = get-ProcessProperty

# Show Processes that started or stopped
Compare-Object @($psold.keys) @($psnew.keys) |%{
$Id = $_.inputObject
if ($_.Sideindicator -eq '=>')
{
$Name = ($psnew[$id]).Name
"$timestamp Start $Id $Name"
}
if ($_.Sideindicator -eq '<=')
{
$Name = ($psold[$id]).Name
"$timestamp $Id $Name stop"
}
}
$psold = $psnew

# the following code is special to a problem on my Windows 7 installation
# my problem is, when Current Disk Queue Length > 0, but Disk Transfers/sec 0
if ($diskQueue -gt 0 -and $transfer -eq 0)
{
$msg
}
}

Using PowerShell to log Start and Stop of Processes and watch some counters

Merry Christmas everyone.

Today I show a little of PowerShell script, which logs when processes start and when they end.

I wrote it, because I have a very unique problem with my Windows 7. Every now and then (that may be between 10 minutes and 4 hours, my system becomes unresponsive for about 60 seconds, while the the hard drive does some mystic thing.
After a lot of logging with PowerShell I came to the conclusion, that there is a definite correspondance between the length of the Current Disk Queue Length and my problem. Especially when Disk Transfers/sec stays at 0.

The current script helps me to determine the exact time when the problem occurs.
But I didn't yet find any corresponding entries in the event-log nor could I determine the process causing this issue.

           

$psold = get-Process

(
'\PhysicalDisk(_total)\Current Disk Queue Length',
'\PhysicalDisk(_total)\Disk Transfers/sec'
) | Get-Counter -cont -sample 1 |% {
$timestamp = "{0:T}" -f $_.Timestamp

$diskQueue = ($_.CounterSamples[0]).CookedValue
$transfer = ($_.CounterSamples[1]).CookedValue

$msg = "{0} {1,4:f0} {2,4:f0}" -f $timestamp, $diskQueue, $transfer

$psnew = get-Process

# Show Processes that started or stopped
Compare-Object $psold $psnew |%{
$ipo = $_.inputObject
$Name = $ipo.ProcessName
$Id = $ipo.Id
if ($_.Sideindicator -eq '=>')
{
"$timestamp Start $Id $Name"
}
if ($_.Sideindicator -eq '<=')
{
"$timestamp Stop $Id $Name"
}
}
$psold = $psnew

# the following code is special to a problem on my Windows 7 installation
# my problem is, when Current Disk Queue Length > 0, but Disk Transfers/sec 0
if ($diskQueue -gt 0 -and $transfer -eq 0)
{
$msg
}
}
A typical output on my system looks like this

PS C:\Var\bin> C:\Var\bin\topics\Perfmon\disk2.ps1
11:49:28 Start 7840 MultipleFirefoxLoader
11:49:30 Start 7036 firefox
11:49:30 Stop 7840 MultipleFirefoxLoader
11:50:16 Stop 6176 SearchFilterHost
11:50:16 Stop 3664 SearchProtocolHost
11:50:31 Stop 7036 firefox
11:50:44 Stop 1936 WmiPrvSE
11:51:23 1 0
11:52:44 1 0
11:54:44 1 0
11:54:47 1 0
11:54:48 1 0
11:54:49 1 0
11:54:51 4 0
11:54:52 4 0
11:54:53 9 0
11:54:54 9 0
11:54:55 10 0
11:54:56 10 0
11:54:57 10 0
11:54:59 10 0
11:55:00 11 0
11:55:01 11 0
11:55:02 11 0
11:55:03 11 0
11:55:04 11 0
11:55:05 11 0
11:55:06 11 0
11:55:08 11 0
11:55:09 11 0
11:55:10 11 0
11:55:11 12 0
11:55:12 15 0
11:55:13 Start 3252 audiodg
11:55:13 16 0
11:55:14 17 0
11:55:16 17 0
11:55:17 17 0
11:55:18 17 0
11:55:19 18 0
11:55:20 Start 5028 svchost
11:55:20 19 0
11:55:21 19 0
11:55:23 19 0
11:55:24 20 0
11:55:25 20 0
11:55:26 20 0
11:55:27 20 0
11:55:28 20 0
11:55:29 20 0
11:55:31 20 0
11:55:32 20 0
11:55:33 21 0
11:55:34 21 0
11:55:35 21 0
11:55:36 21 0
11:55:37 22 0
11:55:38 22 0
11:55:40 22 0
11:55:41 22 0
11:56:12 Stop 7712 chrome
11:56:28 Start 7712 chrome


In Resource Monitor that looks like this:

Samstag, 5. Dezember 2009

Using PowerShell to filter the eventlog

Since I'm using Windows 7 in a domain where we use Microsoft Forefront Client Security I have a little problem. About every 60 minutes my computer becomes unresponsive for about 60 seconds, the hard disk led is on.

In the Application Eventlog I find pairs of Events 21268, 21269. Googling around I seem to be the only one with this special problem.

Some hints say my domain admin has to change some settings, so that my local computer can increase a local buffer. Chances to convince the forefront guys that they do some real nonsence here ( why not just ask me, whether I allow to increase the buffer) or to convince my admin to get some advice from his forefront consultant seem very low.

What the hell fills the buffer. Looking at the Security log, I see that there are lots of audit Failures.

OK, I'm not interessted in audit fails, I don't want to log them. No chance some domain policy doesn't allow me to switch off auditing of rejected packages.

Oh funny thing: I'm allowed to disable the firewall. I'm not going to try this option.

It's time to look deeper into Microsoft Eventlogs.

Seems they are very legacy application, like ipconfig and inifiles. Main information is returned as name:value pairs in plan text.

The Windows Filtering Platform has blocked a connection.

Application Information:
Process ID: 1020
Application Name: \device\harddiskvolume2\windows\system32\svchost.exe

Network Information:
Direction: Inbound
Source Address: 192.168.1.33
Source Port: 60100
Destination Address: 168.143.162.100
Destination Port: 443
Protocol: 0

Filter Information:
Filter Run-Time ID: 212121
Layer Name: Receive/Accept
Layer Run-Time ID: 44


It's time to use a little PowerShell, to convert eventlog data to properties of PowerShell objects, which can be grouped etc.

function Convert-PairToProperty2            
{
process
{
$hash = @{}

$_ -split "`r?`n" | % {
if (.{$m = [regex]::Matches($_,'(\w.*?):\s*(.*)');$m[0]})
{
# Write-Host $m[0].groups[1].value
# Write-Host $m[0].groups[2].value
$hash[ ($m[0].groups[1].value)] = ($m[0].groups[2].value)
}
}
New-Object PSObject -Property $hash
}
}

if ($False)
{
'abc:123
efg:456'
|Convert-PairToProperty2
}

if (! $seclog_1000)
{
Write-host "Collecting last 1000 packets rejected"
(Measure-Command{$seclog_1000 = get-Eventlog security -InstanceId 5152 -newest 1000 | select message }).Milliseconds
}
else
{
'Using $seclog_1000'
}
$time_property2 = Measure-Command { $property2 = ($seclog_1000 | Convert-PairToProperty2) }

"needed $($time_property2.Milliseconds) for property2"

$property2 |group-object -property 'Source Address' -noelement |Sort-object count -desc



If you are taking a closer look, you see that I used http://blogs.msdn.com/powershell/archive/2009/12/05/new-object-psobject-property-hashtable.aspx to convert a hash to properties.

I tried different variants, but performance measurements don't show clear preferences for one or the other.

What I got is clear information which ip address causes most rejected packages.

Donnerstag, 26. November 2009

And now using the data to generate sql INSERT-statements

Before SQL-Serve 2008 sql bulks of SQL Insert-Statements are so redundant, that they are not readable.
Of corse, if you are too clever you ommit the column list after INSERT INTO.
Try it and learn it the hard way.

One of my common tasks is generating Insert Statements. Perhaps this way:


$list = (             
( 1, 'PS', 'PowerShell is the most inovative scripting language'),
( 2, 'Python', 'has the most concise formating'),
( 3, 'Algol60', 'the mother of quoted identifiers'),
( 4, 'Algol68', 'the root of array slicing'),
( 5, 'c#', 'if only you were caseinsentitiv casesensitivity is ORACLE''s greates fault'),
( 6, 'SQL', 'has an Insert syntax which is worse than Street Basic''s Data-Statement
(where we put the assembler code you remember)'
)
)

foreach ($item in $list)
{
$id, $code, $note = $item
$note = $note -replace "'", "''" # you have to double embedded apostrophes
"insert into Computer_Languages ( Id, Code, Note) values ( $id, '$code', '$note')"
}

Background to problem with nested data structures

Thanks Jeff for the quick response. For some reasons I memorized the following pattern:

$list = @(            
(1,2)
(3,4)
)
$list.count



which flattens the structure and yields 4 instaed of the correct syntax

$list = (            
(1,2),
(3,4)
)
$list.count



which yields 2

Once using the wrong pattern there is no escape without help.

In Python it would be basic. in PowerShell ???

I hope there is a better solution in Powershell to build $list

$list = @()            

function add-Tupple
{
$index = $list.count
$global:list += 1
$global:list[$index] = $args
}


add-Tupple 'Ps' 'has object pipelines'
add-Tupple 'Python' 'has natural nested datastructures'

$list.count

foreach ($item in $list)
{
$code, $name = $item
"Code: $code"
"Name: $name"
}

# in python (('Ps', 'has object pipelines'), ('Python', 'has natural nested datastructures'))

Sonntag, 15. November 2009

Manage Modules The ISE Way

Hello again

Last month we got a lot of modules to try. Example given PowerShellPack or BSonPosh Powershell Module.

Of corse you do not want to add all the modules you find to your profile.
To be honest isepack is the only module I load in my profile.
I just added a smal script to my personal toolbox of ISE Add-On Extensions.

It adds and removes modules, list the currently loaded and shows the files of a module.

Pleae be warned, not all modules are writen to be removed, e.g. ispack does not remove its menus, when removed. But you have a starting point to play with.

And thanks again to James Brundage, whoes Copy-ColoredHTML (it's in the ISEpack module of the PowerShellPack) makes posting PowerShell code so easy.

function Update-ModuleMenu()            
{
$all_modules = get-module -list
$loaded_modules = get-module

$remove_items = @{}
$loaded_modules | % {
$name = $_.name
$remove_items[$_.name] = "Remove-module $name; Update-ModuleMenu"
}

$add_items = @{}
$all_modules | ? {! ($loaded_modules -contains $_ )} |
% {
$name = $_.name
$add_items[$_.name] = "Import-module $name; Update-ModuleMenu"

$list_items = @{}
$all_modules | % {
$list_items[$_.name] = "gci (split-path (get-module $_ -list).Path) | select Name"
}

$items = @{
" loaded" = {Get-Module | Sort-object | select name, path | fl}
" add" = $add_items
" remove" = $remove_items
"files" = $list_items
}
}

#$items

Add-IseMenu -name 'Module' $items
}


Update-ModuleMenu

Donnerstag, 12. November 2009

Reload-ISE - Part III

I added some code to save using different encodings and to show the encoding of the current file.

I thought default for new files was utf8. Surprize it is BigEndianUnicode. But as long as it uses a BOM-Mark i will not complain. (Otherwise read my comments. ;-) )

Play and learn.


            
[cmdletbinding()]
param(
# use this switch, when you have ISEpack installed and want a default menu added
# import-module isepack
# . -ISEpackCX
[switch]$ISEpackCX
)


function Reload-ISE ()
{
<#
.Synopsis
Reload file asuming given encoding
.Description
Reload the file in the current editor asuming given encoding,
the file is not saved automatically. You can try other encondings on
the unmodified file.
.Example
Reload-ISE utf8
Reloads the file asuming utf8 encoding. This is useful when the file
has no BOM
.Example
Reload-ISE
Prompts for a codepage number and reloads the file using it
.LINK
Script posted to:
http://pauerschell.blogspot.com
by Bernd Kriszio (twitter: bernd_k)
.Parameter encoding
encodings known to Get-Content:
Unknown, String, Unicode, Byte, BigEndianUnicode, UTF8, UTF7, Ascii
for a list of valid codepages see
http://msdn.microsoft.com/en-us/library/system.text.encodinginfo.aspx
.NOTES
use -verbose to show the current encoding of the reloaded file
and RMFC read my f... comments
#>

[cmdletbinding()]
param(
# encoding to use for reloading
[Parameter(Position = 0, Mandatory=$True)]
$encoding
)
$path = $psise.CurrentFile
$fullpath = $path.FullPath

if ( ("String", "UTF8", "UTF7", "Ascii", "Unicode", "BigEndianUnicode") -contains $encoding)
{
$text = Get-Content -Encoding $encoding $fullpath -ReadCount 0 -totalcount -1
$text = $text -join "`r`n"
}
else
{
$encoding = [int]$encoding
$bytes = get-content $fullpath -encoding byte
$encoding_obj = [System.Text.Encoding]::GetEncoding( $encoding )
$text = $encoding_obj.GetString($bytes)
}

$loadToNewEditor = $False
if ($loadToNewEditor )
{
$count = $psise.CurrentPowerShellTab.Files.count
$psIse.CurrentPowerShellTab.Files.Add()
$Newfile = $psIse.CurrentPowerShellTab.Files[$count]
$Newfile.Editor.Text = $text
}
else
{
$psise.CurrentFile.Editor.Text = $text
}
$psISE.CurrentFile.Encoding | Write-Verbose
}


if ($ISEpackCX)
{
# I'm beginning to dislike Add-IseMenu because I can't control the order of the items, I'm using blanks as workaround. Dirty old...
Add-IseMenu -name 'Reload/Save' @{
" Show encoding" = {$psISE.CurrentFile.Encoding| Select BodyName, IsSingleByte, EncodingName, CodePage| fl}
"Reload Codepage..." = { Reload-ISE } # in most cases you can't save back in this encoding, only export
"Reload Ascii" = { Reload-ISE Ascii }
"Reload BigEndianUnicode" = { Reload-ISE BigEndianUnicode } # this seems to be the default for new files in ISE
"Reload OEM850" = { Reload-ISE 850 } # you can't save back in this encoding, only export
"Reload String" = { Reload-ISE String } # seems to be the same as unicode
"Reload Unicode" = { Reload-ISE Unicode }
"Reload utf7" = { Reload-ISE UTF7 }
"Reload utf8" = { Reload-ISE UTF8 }
# To save means use an encoding, which ISE can read back again
"Save File ASCII" = {$psISE.CurrentFile.Save([Text.Encoding]::ascii)} # if you use this, you are insulting most Europeans
"Save File ANSI" = {$psISE.CurrentFile.Save([Text.Encoding]::default)} # my personal favorite ;-)
# I hope the following write BOM's. Unicode without BOM is more evil than OEM437 or OEM850
# I sentence everyone who uses unicode without BOM to 10 years VB3 coding
# (without PowerShell and on Vista to make it a real punishment ;-) )
"Save File utf7" = {$psISE.CurrentFile.Save([Text.Encoding]::utf7)}
"Save File utf8" = {$psISE.CurrentFile.Save([Text.Encoding]::utf8)}
"Save File unicode" = {$psISE.CurrentFile.Save([Text.Encoding]::unicode)}
"Save File BigEndianUnicode" = {$psISE.CurrentFile.Save([Text.Encoding]::BigEndianUnicode)} # as far as I know, that's ISE's default for new files
# Todo: Export in arbritary encodings into another file
}
}

Mittwoch, 4. November 2009

Reload-ISE - part II

I have extended my function, so that it now handles all Code Page numbers, like OEM 850, OEM 437 or whatever is listed in http://msdn.microsoft.com/en-us/library/system.text.encodinginfo.aspx. I even tried to make the header more standard.

This file is written in a special way, which I call ISEpackCX.
It can use ISEpack's Add-IseMenu to extend the Add-ons menu. If you wish, you can do without this and take care of the menu by your own.

Add the following lines to your profile

import-module isepack            
#. <your path>\Reload-ISE.ps1 -ISEpackCX


and save the following as Reload-ISE.ps1.

Happy ISE-extending

Bernd


          
[cmdletbinding()]
param(
# use this switch, when you have ISEpack installed and want a default menu added
# import-module isepack
# . -ISEpackCX
[switch]$ISEpackCX
)


function Reload-ISE ()
{
<# .Synopsis Reload file asuming given encoding .Description Reload the file in the current editor asuming given encoding, the file is not saved automatically. You can try other encondings on the unmodified file. .Example Reload-ISE utf8 Reloads the file asuming utf8 encoding. This is useful when the file has no BOM .Example Reload-ISE Prompts for a codepage number and reloads the file using it .LINK Script posted to: http://pauerschell.blogspot.com by Bernd Kriszio (twitter: bernd_k) .Parameter encoding encodings known to Get-Content: Unknown, String, Unicode, Byte, BigEndianUnicode, UTF8, UTF7, Ascii for a list of valid codepages see http://msdn.microsoft.com/en-us/library/system.text.encodinginfo.aspx .NOTES use -verbose to show the current encoding of the reloaded file #>
[cmdletbinding()]
param(
# encoding to use for reloading
[Parameter(Position = 0, Mandatory=$True)]
$encoding
)
$path = $psise.CurrentFile
$fullpath = $path.FullPath

if ( ("String", "UTF8", "UTF7", "Ascii", "Unicode", "BigEndianUnicode") -contains $encoding)
{
$text = Get-Content -Encoding $encoding $fullpath -ReadCount 0 -totalcount -1
$text = $text -join "`r`n"
}
else
{
$encoding = [int]$encoding
$bytes = get-content $fullpath -encoding byte
$encoding_obj = [System.Text.Encoding]::GetEncoding( $encoding )
$text = $encoding_obj.GetString($bytes)
}

$loadToNewEditor = $False
if ($loadToNewEditor )
{
$count = $psise.CurrentPowerShellTab.Files.count
$psIse.CurrentPowerShellTab.Files.Add()
$Newfile = $psIse.CurrentPowerShellTab.Files[$count]
$Newfile.Editor.Text = $text
}
else
{
$psise.CurrentFile.Editor.Text = $text
}
$psISE.CurrentFile.Encoding | Write-Verbose
}


if ($ISEpackCX)
{
# activate only those you need
# this is not stupid SQL-Management-Studio with no selection or select from all posible encodings
Add-IseMenu -name 'Reload' @{
" Codepage..." = { Reload-ISE }
"Ascii" = { Reload-ISE Ascii }
"BigEndianUnicode" = { Reload-ISE BigEndianUnicode }
"String" = { Reload-ISE String }
"Unicode" = { Reload-ISE Unicode }
"UTF7" = { Reload-ISE UTF7 }
"UTF8" = { Reload-ISE UTF8 }
}
}

Dienstag, 3. November 2009

Reload-ISE

Just had to work with some data in utf-8 without BOM. I want to extend this to OEM-850 later, but here the first draft.

And if you are really using ISE for productive things please send me (bernd_k) a note at twitter.

Sometimes I believe I'm the only one. At least in https://twitter.com/bernd_k/ise-users. I want to add you.

Feedback will improve my presentation. Otherwise you get it quick and dirty.

The function Add-IseMenu is in ISEpack http://code.msdn.microsoft.com/PowerShellPack.

Have fun with ISE

Bernd

           
function Reload-ISE ($encoding = 'UTF8')
{

# ToDo OEM 850 requires .NET
# Get-Content Encodings: Unknown, String, Unicode, Byte, BigEndianUnicode, UTF8, UTF7, Ascii

$path = $psise.CurrentFile
# $path
$fullpath = $path.FullPath
# $fullpath
$text = Get-Content -Encoding $encoding $fullpath -ReadCount 0 -totalcount -1

$text = $text -join "`r`n"

# $count = $psise.CurrentPowerShellTab.Files.count
# $psIse.CurrentPowerShellTab.Files.Add()
# $Newfile = $psIse.CurrentPowerShellTab.Files[$count]
# $Newfile.Editor.Text = $text

$psise.CurrentFile.Editor.Text = $text
}


Add-IseMenu -name 'Reload' @{
"String" = {Reload-ISE "String"}
"UTF8" = {Reload-ISE "UTF8"}
"UTF7" = {Reload-ISE "UTF7"}
"Ascii" = {Reload-ISE "Ascii"}
"Unicode" = {Reload-ISE "Unicode"}
"BigEndianUnicode" = {Reload-ISE "BigEndianUnicode"}
#"OEM850" = {Reload-ISE "OEM850"}
}

Sonntag, 25. Oktober 2009

Hello ISEpack

Hello PowerSheller Users,
now that Windows 7 is available and the most important event of the year PowerShell v2 Virtual Launch Party is history and James Brundage has buried as under tons of new functions in the PowerShell Pack
hopefully the last installations of PowerShell V2 CTP are replaced by the V2 RTM or V2 RC if you have a downgrade system.

ISE the Integrated Scripting Environment provides Windows conform copy & paste shortcuts. Thanks.

Any case, if you are completely new to PowerShell, it is better if you start with some GUI tool perhaps the free PowerGui or the commercial PowerShell Plus v3.0 , which have a lot of Intellisense build in. If you are interessted inother alternatives I recommend install Shay Levy's PowerShell Toolbar
. The link to the download is a little hidden, just above the comment section. Then go to resources | Script Editors.

These tools are kind of studios. They have some start-up time additional to that caused by your profile scripts and they try to help you in avoiding making mistakes by adding intellisense.

ISE is somewhat other. When you start it for the first time and scan through its menus you get the strong impression that there is something missing. For example: print, recently used files, ....

You are right, but there is something you don't see until you run some suitable script or import a module. ISEPack from the PowerShell Pack is one of these Modules:

import-module isepack

Afterwards the Add-ons menu appears. That is the magic location where you can extend ISE with all kinds of things you can sensibly do. And even some more.

There is an older Code Plex Project PowerShell ISE-Cream
which stagnated the last month due to PowerShell V2 CTP3 - V2 incompatibilities. I hope we will come back to life now.

My advice is please study ISEpack first and try ISE-Cream later. ISE-Cream is open and you too can contribute.

But now let us explore ISEPack a bit.

pushd "$(split-path $profile)\modules\isepack"         
Get-ChildItem


The most important file here is IsePack.psm1 . Here you find the code that constructs the add-ons menu.

You have qualms to modify JB's code.

No problem, you leave it as it is and add to the menu in another script:

Add-IseMenu -Name "My Extensions" @{                      
"Save File AS ANSI" = { $psISE.CurrentFile.Save([Text.Encoding]::default) } |
Add-Member NoteProperty ShortcutKey "ALT+Shift+A" -PassThru
}

Please note that I use default here and not ascii. Ascii is 7-bit only an not suitable for the german and many other western European languages.

Damned I forgot to take my chance at the launch party to ask Jeffrey, why there is a value called default, which isn't used by default.

I hope this helps to take the very first steps into the word of ISE Extensions.

Bernd