PowerShell.cz
Get-World | ConvertTo-PowerShell
Get-World | ConvertTo-PowerShell
Jan 7th
Today I was heavily working with PowerShell help system. And was tired to call it using Get-Help cmdlet. So I created small function which I put to my profile:
function Show-HelpAboutFunction { $topics = Get-Help about_* foreach ($t in $topics) { $tn = $t.Name -replace 'about_', 'abt-' $text = "function global:$($tn) { Get-Help $($t.Name) }" Invoke-Expression "$text" } }
So when in console I can write: abt-func<Tab> and can circulate help topics till have the one I need. I know that for some topics is better to write Get-Help with partial help topic name, but in some cases I like my solution more.
Note: I know that abt is not approved verb
Jan 1st
I was working in ISE pretty much during last two days (oh yes, was nice end of 2011 and beginning of 2012). During script creation I was checking values of variables frequently. Wouldn’t be nice to see variables value and not just write it’s name to Command Pane? So I came with another menu Add-on command.
function GetValues { $content = $psISE.CurrentFile.Editor.Text $tokens = [System.Management.Automation.PsParser]::Tokenize($content, [ref] $null) |? {$_.Type -eq 'Variable'} | Sort Content -Unique foreach ($t in $tokens) { $prop = @{ Name = $t.Content Value = Get-Variable -Name $($t.Content) -ValueOnly -ErrorAction SilentlyContinue } New-Object -TypeName PSObject -Property $prop | Select Name, Value } } $psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('Show values',{GetValues},'CTRL+SHIFT+V') | Out-Null
When you work with any script, you can run it and will see all actual script variables in Output Pane.

Using Tokenizer API I received all variables from current script and created new object with variable name and value. Then it’s send to output. I am thinking about some graphical output (WPF or ShowUI) or just to Out-GridView. There are also some another points to update but for my current needs it’s OK.
Jan 1st
I like one of new PowerShell v3 features. When you are in ISE and want to run current line, just press F8, it’s no more necessary to select the line and then use Run Selection (F8). I’d like to have it in v2 also so I created another quick function:
function RunLine { $editor = $psISE.CurrentFile.Editor $currentLine = $editor.CaretLine $currentLineLength = $editor.GetLineLength($currentLine) $currentPosition = $editor.CaretColumn $psISE.CurrentFile.Editor.Select( $currentLine, 1, $currentLine, $currentLineLength + 1 ) "Running >> $($psISE.CurrentFile.Editor.SelectedText)" Invoke-Expression $psISE.CurrentFile.Editor.SelectedText $psISE.CurrentFile.Editor.Select( $currentLine, $currentPosition, $currentLine, $currentPosition ) } $makovecRoot = $psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add("Makovec", $null, $null) $makovecRoot.Submenus.Add('Run line',{RunLine},'CTRL+F8') | Out-Null
It allows me to be at some line and by pressing Ctrl+F8 just run it:

If you want to see another cool new features in ISE v3, go to Windows Management Framework 3.0 CTP2 page and download document named Windows PowerShell ISE.pdf.
Dec 28th
Today I was playing with PowerShell v3 and was frequently working inside ISE (love it’s Intellisense feature). I was in this situation few times:

As you can see, cursor is at position 0. At this time I want to add new line, so it means go to end of current line and press Enter. I wanted to automate it. Fortunately ISE object model is self-descriptive, so I created this small Add-on:
$psise.CurrentPowerShellTab.AddOnsMenu.Submenus.Add(
'Insert line below',
{
$psise.CurrentFile.Editor.Select(
$psise.CurrentFile.Editor.CaretLine,
$psise.CurrentFile.Editor.GetLineLength($psise.CurrentFile.Editor.CaretLine)+1,
$psise.CurrentFile.Editor.CaretLine,
$psise.CurrentFile.Editor.GetLineLength($psise.CurrentFile.Editor.CaretLine)+1)
$psise.CurrentFile.Editor.InsertText("`n")
}, "CTRL+ENTER")
$psise.CurrentPowerShellTab.AddOnsMenu.Submenus.Add(
'Shift line',
{
$psise.CurrentFile.Editor.Select(
$psise.CurrentFile.Editor.CaretLine, 1,
$psise.CurrentFile.Editor.CaretLine, 1)
$psise.CurrentFile.Editor.InsertText("`n")
$psise.CurrentFile.Editor.Select(
$psise.CurrentFile.Editor.CaretLine-1, 1,
$psise.CurrentFile.Editor.CaretLine-1, 1)
}, "CTRL+SHIFT+ENTER")
I added two features: add line below and before (shift line). You can call it either from menu:

or via keyboard shortcuts.
Sep 15th
As you all already read during last day, Microsoft showed Windows 8 at it’s Build conference. There are big changes in OS and I am sure there will be tons of articles about it. But for PowerShell enthusiasts in means something else. PowerShell version 3 is a part of new OS
Today, lot of people mentioned the most obvious changes/news/thoughts. To name a few:
After first check, I like following points:
Unfortunately I had to work today, so had not as many time as I wanted for some searching
Fortunately – will have holiday for next three weeks, so there will be enough time for other posts.
Sep 11th
It’s a year now since I bought Kindle for me. I have it still with me and frequently need to check PowerShell documentation. It led me to previous articles (1st and 2nd part) where I described in general, how to convert CHM file to MOBI. As I needed to automate it a bit, I created simple module for conversion process. Whole process is simple:
To run it successfully, you need to have kindlegen installed on your computer and need to set alias kg to point to EXE file. On my PC I did it this way:
[11]: Get-Alias kg | ft -auto CommandType Name Definition ----------- ---- ---------- Alias kg Dropbox:\Ruzne\KindleGen\kindlegen.exe
This is example output when generating file for PowerShell help topics (I recommend to use -Verbose parameter so you’ll see actual state of processing):
[16]: Convert-ChmToMobi .\PSHelp.chm *********************************************** * Amazon.com kindlegen(Windows) V1.1 build 99 * * A command line e-book compiler * * Copyright Amazon.com 2010 * *********************************************** opt version: try to minimize (default) Info(prcgen): Added metadata dc:Title "Title" Info(prcgen): Added metadata dc:Date "2011/09/11" Info(prcgen): Added metadata dc:Creator "moravec" Info(prcgen): Added metadata dc:Subject "Subject" Info(prcgen): Added metadata dc:Description "Description" Info(prcgen): Parsing files 0000374 Warning(prcgen): <INPUT>, <SELECT> or <TEXTAREA> tag does no Info(prcgen): Resolving hyperlinks Info(prcgen): Resolving start reading location Info(prcgen): Added metadata Start reading "5098" Info(prcgen): Computing UNICODE ranges used in the book Info(prcgen): Found UNICODE range: Basic Latin [20..7E] Info(prcgen): Found UNICODE range: General Punctuation - Windows 1252 [201C..201E] Info(prcgen): Found UNICODE range: Latin-1 Supplement [A0..FF] Info(prcgen): Building MOBI file, record count: 0001986 Info(prcgen): Compiling HTML Parser restart information Info(prcgen): Final stats - text compressed to (in % of original size): 040.46% Info(prcgen): The document identifier is: "Title" Info(prcgen): The file format version is V6 Info(prcgen): Saving MOBI file Info(prcgen): MOBI File successfully generated!
There are still some points I need to update or change. For example:
Aug 14th
I received DVDs from MMS on Monday. What a nice day
As I wasn’t in Vegas, these DVDs are opportunity to see all those interesting presentations at home. My wife was out of town this weekend so I had a plan – MMS party
Wanted to watch everything I marked as interesting. My idea was to create one DVD with presentations I selected and play it on TV (and preferably do not leave my bed).
I moved selected folders to one place, you can see structure of BA02 session folder here (it’s the same for all sessions):

In directory with session code is places file video.wmv. Eh – not so good to place every video to root of DVD. So I opened explorer and copied every WMV file to specific location, changed it’s name to session code and did the same for all sessions I selected used PowerShell to process all files. BTW: If you like Show-Tree, it’s part of PowerShell Community Extensions.
First I wanted to save session names so I’ll be able to check session content based on file name (ba02.wmv). One place, where the session name is mentioned, is second line of media.js file:

PS ToBurn:\> Get-ChildItem -Include media.js -Recurse |% { (Get-Content $_)[1] -match ‘^{“title”:”(.*?)”,’ | Out-Null; $matches[1] }
BA01 – Configuration Manager State of the Union
BA02 – Configuration Manager 2007 R3: Technical Update
BA03 – Configuration Manager 2012 – Technical Overview
BA04 – Configuration Manager 2012: Application Management (Part 1 of 3)
BA05 – Configuration Manager 2012: Application Management (Part 2 of 3)
BA06 – Configuration Manager 2012: Migrating from 2007 to 2012
…
As I was working in console (I use aliases as much as possible) and wanted to store this list for future check, my actual command was:
PS ToBurn:\> ls -i media.js -r |% { (gc $_)[1] -match ‘^{“title”:”(.*?)”,’ | Out-Null; $matches[1] } | Out-Printer
Voila – Out-Printer useful again
Second I needed to move video files to my burn folder and rename it.
PS ToBurn:\> ls -i video.wmv -r |% { Move-Item $_ -Destination $(‘ToBurn:\’+$(Split-path $_.DirectoryName -Leaf)+’.wmv’) }
For all WMV files, I moved them to root of ToBurn PSDrive and renamed based on pattern <folder_name>.wmv.
Last point was to remove everything except video files:
PS ToBurn:\> ls * -r |? {$_.name -notlike ‘*.wmv’} | del -force
OK – then just burn what I just selected and MMS party can begin.
Conclusion: When I put DVD to my player, it reported: “Resolution not supported.” So I used my common solution: notebook + VGA cable.
Apr 30th
I like PowerShell books. Every time I hear about a new one, I am impatiently waiting, or – even better – I immediately buy it in some version of early access program. That’s why I like Manning‘s MEAP (Manning Early Access Program). If you don’t know it – you’ll pay a price for electronic version of book and as soon new chapter is finished by author, you receive it in PDF. You can read the book during it’s creation and you can also post your comments (or errors you find) to Author forum so you can influence final version of the book. I like it as it’s a way how I personally can give something back to PowerShell community.
Last addition to my library is book from Don Jones – Learn Windows PowerShell in a Month of Lunches. Don is well known author, speaker and trainer and he’s also PowerShell MVP. I like what Jeffrey Snover wrote about Don: “If you ever find yourself thinking Don is wrong about something he says about PowerShell, your best bet is to double check first. I invented the thing and that is MY policy. (seriously)”. You can find whole “funny” discussion here.
Basic idea of the book is easy – every chapter will take you an hour so you can study it during your lunch. I did it this way during Early Access period and can say it works. I took my notebook to our company’s cafeteria I spent nice times with learning. What’s inside the book? You can find whole table of contents at Manning web but let me mention the chapter I found most useful for me (Please note – it’s my personal opinion, don’t want to tell that other chapters are not useful!).
Every main chapter of the book contains also Lab section, so you can practice what you learned. Most chapters contains also Common points of confusion part – here Don mentions commons mistakes he frequently see when teaching PowerShell – so you can avoid it in your life.
There is also support web page you can use. It’s accessible at morelunches.com and contains all lab answers. Best part of the web are video demos for every chapter – I found it pretty useful. You can find more videos at Don’s YouTube Channel.
Even this book is intended for administrators who are starting with PowerShell, I can say that also intermediate users can learn something useful. Starting today, if someone ask me what to recommend for PowerShell newbie, this book is my answer.
Apr 2nd
This week, James Brundage posted article named Two Ways to Time PowerShell Commands. There was mentioned very neat trick to check running time of last command. Please read that article first to understand what I am talking about.
I created a function to have easier way to call that command. It’s not so hard, so here is it:
function Get-HistoryItemRunningTime { <# .SYNOPSIS Displays running for given item from history .DESCRIPTION For given history ID (or last command) displays running time. .PARAMETER Id Specifies history ID to be used. .INPUTS None. You cannot pipe objects to Get-HistoryItemRunningTime. .OUTPUTS System.TimeSpan. .EXAMPLE C:\PS> Get-HistoryItemRunningTime 3 Days : 0 Hours : 0 Minutes : 0 Seconds : 0 Milliseconds : 578 Ticks : 5781250 TotalDays : 6.69126157407407E-06 TotalHours : 0.000160590277777778 TotalMinutes : 0.00963541666666667 TotalSeconds : 0.578125 TotalMilliseconds : 578.125 Displays running time for command ID #3. .EXAMPLE PS C:\> Start-Sleep 2 PS C:\> Get-HistoryItemRunningTime Days : 0 Hours : 0 Minutes : 0 Seconds : 2 Milliseconds : 15 Ticks : 20156250 TotalDays : 2.33289930555556E-05 TotalHours : 0.000559895833333333 TotalMinutes : 0.03359375 TotalSeconds : 2.015625 TotalMilliseconds : 2015.625 Displays running time for last command. .LINK Get-History #> param ( [int64]$Id ) if ($Id) { $history = Get-History -Id $Id } else { $history = Get-History -Count 1 } return ($history.EndExecutionTime - $history.StartExecutionTime) }
I then decided to make it a bit more useful. What to put it to profile? Hmm. So I modified also my prompt function.
Note: I have fully customized prompt in my profile. In following example I just show the idea, not my current prompt.
$OrigTitle = $host.UI.RawUI.WindowTitle $ShowRunningTime = $false function prompt { if($ShowRunningTime) { $host.UI.RawUI.WindowTitle = "$OrigTitle Time: $(Get-HistoryItemRunningTime)" } else { $host.UI.RawUI.WindowTitle = $OrigTitle } }
So now I can run it this way

and if you don’t want to see the time in title, you can just run it for specific history item (please note that ghit is an alias for Get-HistoryItemRunningTime).
PS> h
Id CommandLine
– ———–
1 ghit
2 Start-Sleep 2
3 gps | Out-Null
4 get-date
PS> ghit 2
Days : 0
Hours : 0
Minutes : 0
Seconds : 2
Milliseconds : 15
Ticks : 20156250
TotalDays : 2.33289930555556E-05
TotalHours : 0.000559895833333333
TotalMinutes : 0.03359375
TotalSeconds : 2.015625
TotalMilliseconds : 2015.625
PS> ghit
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 62
Ticks : 625000
TotalDays : 7.2337962962963E-07
TotalHours : 1.73611111111111E-05
TotalMinutes : 0.00104166666666667
TotalSeconds : 0.0625
TotalMilliseconds : 62.5
Thank you, James, for nice trick
Mar 30th
Today I have a quick post. My friend called me that he needs to check SAV definition date which is stored in registry. It is also available in Symantec AntiVirus GUI
![]()
But – unfortunately – the value in registry is hex number which needs to be converted to readable format. Whole idea is described at Symantec’s web. As he was interested in PowerShell solution (another one converted) I quickly created short function:
function Get-SAVdefs { param ($def = (Get-ItemProperty HKLM:\SOFTWARE\INTEL\LANDesk\VirusProtect6\CurrentVersion).UsingPattern ) [Convert]::ToString($def, 2) -match "^(?<year>\d*)(?<month>\d{4})(?<day>\d{5})(?<rev>\d{9})$" | Out-Null "{0}/{1}/{2} Rev {3}" -f $([Convert]::ToInt32($matches.year, 2) + 1998), [Convert]::ToInt32($matches.month, 2), [Convert]::ToInt32($matches.day, 2), [Convert]::ToInt32($matches.rev, 2) }
So it can be used this way:
PS C:\Scripts > Get-SAVdefs
2011/3/29 Rev 5
PS C:\Scripts > Get-SAVdefs 0x312e02
2010/4/23 Rev 2
As a parameter is used direct path to the registry he provided. Then, the value found is processed with regex. It splits binary number based on info found at mentioned web page. Then all values from $matches are written using format operator.
Main work is done with System.Convert class. It contains few methods for converting numbers, for example to convert number 3652 to binary and back, you can use:
PS C:\Scripts > [convert]::ToString(3652, 2)
111001000100
PS C:\Scripts > [convert]::ToInt16(111001000100, 2)
3652
I am sure you will find some other examples how to use it. BTW: Why 3652? Wait till Friday and you’ll see