Get-World | ConvertTo-PowerShell
makovec
This user hasn't shared any biographical information
Homepage: http://www.powershell.cz
Posts by makovec
Book: Learn Windows PowerShell in a Month of Lunches
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!).
- Chapter 3: Using the help system – if there should be just one chapter to read – it’s this one. As PowerShell contains really great help system, if you learn how to use it, you are on a good way to be successful. Sometimes I am surprised how people are unwilling to read help. For me – help is the key to PowerShell mastery.
- Chapter 6: Objects: just data by another name – Whole PowerShell is about objects, so you need to understand what the object is, what is method or property.
- Chapter 7: The pipeline, deeper – another core concept. It’s first touched in chapter four but in this chapter you’ll see what’s ByValue, ByPropertyName or how to use custom properties using Select-Object cmdlet.
- Chapter 13: Working with bunches of objects, one at a time – this chapter shows you when (and why!) to use “direct piping” to cmdlet (Get-Service | Stop-Service), when use ForEach-Object (Get-Service | ForEach-Object { $_.Stop() }) and also mentions some other methods. In this chapter you’ll find how to use pipeline effectively.
- Chapter 17: You call this scripting? – here you’ll find how to create scripts with parameters and it’s own help. This chapter also contains description how pipeline(s) works when calling multiple commands and you’ll learn a bit about scoping.
- Chapter 21: Creating your own “cmdlets” and modules – shows you how to make your functions “pipeline ready” and how to reuse them using modules.
- Chapters 24 & 28 – those are a bit special and contains some useful tips/tricks/gotchas you’ll find during your learning process.
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.
Command running time
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
Virus Definition File version in registry
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
Check your log files on the fly
Mar 23rd
Sometimes I need to check content of specific file. I usually use SMS Trace (part of SMS 2003 Toolkit). If I don’t have SMS Trace but there is PowerShell on the server, I used to use Get-Content cmdlet.
There is one very useful parameter: Wait. It will allow you to see content of the file on-the-fly. So as lines are coming, your console will show it.
Note: Wait is provider specific parameter so you don’t see it when running Get-Help Get-Content. To see it’s description you need to run Get-Help FileSystem.
Right console is updating file and changes are immediately visible in left console (Line 1 – Line 5 were in the file already so are returned immediately) and then console is updated every second with new line (Line 100 – Line 105).
Sometimes it’s not necessary (useful) to see all lines coming to the file. So then is possible to filter what you want to see (I wrote the code in ISE so it’s easier to read):
In the pipeline I am filtering with Where-Object (here represented by it’s alias ‘?’) so see only error lines. Of course, you can use more complex regex for that filtering.
Find path to specific node in SMS console
Jan 12th
Have you ever heard this: “Hey, someone is on holiday so please take care of his work. I need to find info about specific (collection|package|advertisement). Can you please send it to me?” Sometimes it could be a nightmare. Especially if you are looking for collection named This test is what I am looking for and the structure looks like:
Not so funny. Just for this case I created small tool.
Note: Actually I have two separate tools which I want to merge to one. First is written in C# and the screenshot is taken from this one.
It’s now working only for collections and you can filter out collections live – as you are writing requested name to filter field. Second are just functions in PowerShell and I use them for queries against IDs of packages and advertisements. I will talk only about scripts in this article.
WMI behind the code
For work with hierarchy in SMS admin console there are two useful classes: SMS_ObjectContainerItem and SMS_ObjectContainerNode (based on SDK it looks a bit different for SMS2003 and SCCM2007 – of course as it uses different MMC version – so I pointed to newer version – even the script below works with SMS). This code can’t be used for collections as they used different method for storing it’s hierarchy (which is clear if you will think how it works). More info related to collections can be found in SMS_Collection and SMS_CollectToSubCollect MSDN articles.
Get-SMSConsolePath
This is the entry point to functionality. It accepts ID of package or advertisement to look for.
function Get-SMSConsolePath <# .SYNOPSIS Displays path in SMS Console. .DESCRIPTION For given SMS object (package or advertisement) shows full path to this object as it's in SMS Console. .PARAMETER id Id of the object to check .EXAMPLE Get-SMSConsolePath tst00123 Packages/Test/Testing package #> { param ( [Parameter( Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true )] [ValidatePattern("tst[02]0[a-f0-9]{3}")] [string] $id ) BEGIN { $Script:ocn = Get-WmiObject -ComputerName $Global:SMSServer -Namespace $Global:SMSWmiNamespace ` -Class SMS_ObjectContainerNode -Filter "ObjectType IN (2,3)" | Select ContainerNodeID, Name, ObjectType, ParentContainerNodeID } PROCESS { $Script:SMSConsolePath = "" $Script:SMSConsoleItem = "" $container = Get-SMSConsoleContainer $id Get-SMSConsoleParent -currNode $container Write-Host "$Script:SMSConsolePath$Script:SMSConsoleItem" } END { Remove-Variable ocn -Scope Script Remove-Variable SMSConsolePath -Scope Script Remove-Variable SMSConsoleItem -Scope Script } }
You see that in begin section I load data from SMS_ObjectContainerNode and store it for future use. I am filtering the results to have just data for packages and advertisements (ObjectType=2,3). Then call two other support functions in process part and will remove some variables at the end.
Get-SMSConsoleContainer
This is the part where I’ll check actual name of the package/advertisement. I will receive it by linking result from SMS_ObjectContainerItem class and respective class of SMS_Package or SMS_Advertisement.
function Get-SMSConsoleContainer { <# .SYNOPSIS Returns containerID for given object. .DESCRIPTION For given object (based on ID) return its containerID. #> param ( $id ) $filter = "InstanceKey = '" + $id + "' AND ObjectType IN (2,3)" $tmp = Get-WmiObject -ComputerName $Global:SMSServer -Namespace $Global:SMSWmiNamespace ` -Class SMS_ObjectContainerItem -Filter $filter | Select ContainerNodeID, InstanceKey, ObjectType if ($($tmp.ObjectType) -eq '2') { $Script:SMSConsolePath += "Packages" $filter = "PackageID = '" + $tmp.InstanceKey + "'" $Script:SMSConsoleItem = (Get-WmiObject -ComputerName $Global:SMSServer -Namespace $Global:SMSWmiNamespace ` -Class SMS_Package -Filter $filter).Name return $($tmp.ContainerNodeID) } else { $Script:SMSConsolePath += "Advertisements" $filter = "AdvertisementID = '" + $tmp.InstanceKey + "'" $Script:SMSConsoleItem = (Get-WmiObject -ComputerName $Global:SMSServer -Namespace $Global:SMSWmiNamespace ` -Class SMS_Advertisement -Filter $filter).AdvertisementName return $($tmp.ContainerNodeID) } }
Get-SMSConsoleParent
And this is the function which actually resolves parent names. It works recursively from bottom to root folder in console. It uses data stored in $ocn variable and creates final string.
function Get-SMSConsoleParent { <# .SYNOPSIS Returns parent of given object. .DESCRIPTION For current node return it's parent. Used for recursion. #> param ( $currNode ) $parNode = ($Script:ocn |? {$_.ContainerNodeID -eq $currNode}).parentContainerNodeID if ($parNode -ge 0) { Get-SMSConsoleParent $parNode } $Script:SMSConsolePath += "$(($Script:ocn |? {$_.ContainerNodeID -eq $currNode}).Name)/" }
Put it together
As we have everything now (I have all three functions in one module) we can try to do some test.
PS C:\> Get-SmsConsolePath tst00035
Packages/_Global/Windows 7/Adobe/Adobe Reader X – for test
I use this code mainly for documentation purposes. Every time I am reporting to our change request system I just run another function – which uses those mentioned – and it will generate nice table for me. It’s “similar” to this:
PS C:\> remedyTable ‘Adobe Reader X’
Package:
<package info> #here is the path in console also
Collection:
<here is collection info>
Advertisement:
<same as for package>
…
So I am not spending whole day in console looking for settings are other annoying things.
Check refresh time for collections
Jan 7th
It happened to me that during the day I found one of our SMS servers a bit unresponsive. After short investigation I found out that a lot of collections is refreshing at the same time and therefore my refresh was in the queue. As the refresh is by default set for everyday, to the time when the collection was created, it can happen that there are some peaks when most of our collections are refreshing. So I decided to check this.
Looking into SMS SDK I found necessary information
and was able to check RefreshSchedule with Get-WmiObject cmdlet.
__GENUS : 2
__CLASS : SMS_ST_RecurInterval
__SUPERCLASS : SMS_ScheduleToken
__DYNASTY : SMS_ScheduleToken
__RELPATH :
__PROPERTY_COUNT : 8
__DERIVATION : {SMS_ScheduleToken}
__SERVER :
__NAMESPACE :
__PATH :
DayDuration : 1
DaySpan : 1
HourDuration : 0
HourSpan : 0
IsGMT : False
MinuteDuration : 0
MinuteSpan : 0
StartTime : 20040614175400.000000+***
As you can see, StartTime is in standard obscure WMI format and we are able to convert it to standard DateTime format easily (if you want to see more, you can check nice post from Shay Levy).
We have all info so can build short function:
function Get-SMSCollectionRefreshTime { $colls = Get-WmiObject -ComputerName vmsms01 -Namespace root\sms\site_xxx -Class SMS_Collection foreach ($coll in $colls) { $([wmi]"$($coll.__PATH)").RefreshSchedule } }
It will produce long list of refresh schedules for all our collections.
Note: You can see that in the list are some other properties and if you are interested, you can find more at SMS_ST_RecurInterval MSDN page. Most of our collections are set to refresh daily (in case of direct membership we are not refreshing at all) but we have few (three) to refresh more often. In the following code I will count all collections as if they are refreshed daily. If you have more frequently updated collections, you can think about modifying the code.
After some experimenting I came with following code:
Get-SMSCollectionRefreshTime | ` Select @{l="Hour";e={"{0:d2}" -f $([System.Management.ManagementDateTimeConverter]::ToDateTime($_.StartTime)).Hour}} | ` Group Hour | Select Name, Count, @{l="Graph";e={"*"*$($_.Count/2)}} | Sort Name | ft -AutoSize -Wrap
which produced following result:
Name Count Graph
—- —– —–
00 16 ********
02 2 *
03 2 *
04 6 ***
05 10 *****
06 66 *********************************
07 22 ***********
08 94 ***********************************************
09 125 **************************************************************
10 163 **********************************************************************************
11 141 **********************************************************************
12 79 ****************************************
13 86 *******************************************
14 118 ***********************************************************
15 166 ***********************************************************************************
16 101 **************************************************
17 99 **************************************************
18 61 ******************************
19 33 ****************
20 12 ******
21 2 *
22 1
23 12 ******
So based on this result, most of our collections are refreshed during 10AM-11AM and 3PM-4PM intervals. Let me describe the code used.
- First Select is pretty big construction. I used computed value where the conversion from WMI time is running ([System.Management.ManagementDateTimeConverter]::ToDateTime($_.StartTime)), from the result I then used just the hour and format it using –f operator (“{0:d2}” -f $(…)).
- Then Group it based on computed hour so can see frequency during the day. At the first time I stopped here as I already saw requested data (number of collection refreshed at specific time). But to have more fun I continued…
- Select hour, number of collections and show “graph” represented by stars. I found out that because of big peaks it’s better to multiply result by two to have all stars at one screen (“*”*$($_.Count/2)).
- Then I Sort results by hour,
- and Format result as table.
Whole work didn’t take longer than five (OK – maybe 10) minutes and I was able to confirm my first thoughts. Next task is to check collections refreshed in peaks and decide what can be changed to different time (preferably overnight). But – it will be (maybe) another post.
Note: I have small piece of paper hung at my screen in the office. It contains this citation:
I am looking to it during the day and today I confirmed it again.
How to work with KindleGen
Jan 7th
In previous post I showed you the result of my experiment with KindleGen. In this post I’ll describe the workflow I used to generate the file.
KindleGen utility
First of all you need to download KindleGen utility and unpack it to whatever folder you want. I put it to my Dropbox folder to be able to run it on all my computers and then I set an alias for kindlegen.exe file.
PS C:\> Set-Alias -Name kg -Value Dropbox:\Utilities\KindleGen\kindlegen.exe
Amazon provides two samples so can check folders Sample and MultimediaSample for general info.
Starting point – CHM file
As a source I used PowerShell help file located in C:\WINDOWS\help\WindowsPowerShellHelp.chm. CHM is “just” a bunch of HTML pages compiled together. You can see it’s structure for example via 7-Zip.
For us are important those files/folders:
- html folder – contains all topics from CHM file – one HTML page per topic.
- local folder – contains “support” files – pictures used in help, CSS file and JS file.
- PowerShell_GPSplusC.hhc – table of contents for CHM file.
You can grab all of those to your drive by using hh.exe utility.
PS C:\> Get-Command hh.exe | fl
Name : hh.exe
CommandType : Application
Definition : C:\WINDOWS\hh.exe
Extension : .exe
Path : C:\WINDOWS\hh.exe
FileVersionInfo : File: C:\WINDOWS\hh.exe
InternalName: HH 1.41
OriginalFilename: HH.exe
FileVersion: 5.2.3790.2453 (srv03_sp1_qfe.050525-1536)
FileDescription: MicrosoftR HTML Help Executable
Product: HTML Help
ProductVersion: 5.2.3790.2453
Debug: False
Patched: False
PreRelease: False
PrivateBuild: False
SpecialBuild: False
Language: English (United States)
Simply run this command:
PS C:\> hh.exe –decompile hlp c:\windows\help\WindowsPowerShellHelp.chm
and you will see files/folders mentioned above in new hlp folder. You can then check it’s contents to be familiar with the structure.
Let’s build the structure
Now you need to create four files.
- .OPF file – Open Packaging Format file is XML based file and defines “structure” of your final book. More can be found is OPF specification. In Sample folder of KindleGen installation you can check Guide.opf file as it contains also comments to all elements. I used it as a starting point also. Biggest advantage is that it contains information about mandatory elements of the file. Most important elements are: <manifest> – contains list of all files you’ll include in final book. <spine> – ordered (in a way of linear reading) list of HTML files. <metadata> – some general info about final book. As I included cover, it has to be mentioned here.
- .NCX file – Navigation Control file for XML is table of contents. In Sample folder you’ll see some nesting of elements but I found that for my case I was OK with just two levels – chapter and section. On my Kindle I don’t care about five levels as it’s in source CHM file.
- toc.html – Table of contents as it will be shown visually on Kindle. I just used simple <ul> tags to show really basic outline. You can see the picture of my TOC below.
- about.html – some short info about the book.
Two mentioned HTML files are not mandatory but I found useful to include them.
As a resume let’s see what we have now.
Dropbox:\PowerShell\Scripts\Help2Kindle\PowerShellP> ls
Mode LastWriteTime Length Name
—- ————- —— —-
d—- 4.1.11 10:27 PM html
d—- 3.1.11 8:19 PM local
-a— 4.1.11 11:57 AM 810 about.html
-a— 5.1.11 4:41 PM 6616 cover.gif
-a— 4.1.11 5:19 PM 109400 PowerShellP.ncx
-a— 5.1.11 4:49 PM 94708 PowerShellP.opf
-a— 4.1.11 4:58 PM 44067 toc.html
We can go to generate our final MOBI file.
Dropbox:\PowerShell\Scripts\Help2Kindle\PowerShellP> kg .\PowerShellP.opf
***********************************************
* 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 “PowerShell Help”
Info(prcgen): Added metadata dc:Date “2011-01-05″
Info(prcgen): Added metadata dc:Creator “@makovec”
Info(prcgen): Added metadata dc:Publisher “PowerShell.cz”
Info(prcgen): Added metadata dc:Subject “PowerShell Help”
Info(prcgen): Added metadata dc:Description “Help files provided with PowerShell.”
Info(prcgen): Parsing files 0000457
Info(prcgen): Resolving hyperlinks
Info(prcgen): Resolving start reading location
Info(prcgen): Added metadata Start reading “65BE”
Info(prcgen): Building table of content URL: Dropbox:\PowerShell\Scripts\Help2Kindle\PowerShellP\PowerShellP.ncx
Info(prcgen): Computing UNICODE ranges used in the book
Info(prcgen): Found UNICODE range: Basic Latin [20..7E]
Info(prcgen): Found UNICODE range: Letter-like Symbols [2100..214F]
Info(prcgen): Found UNICODE range: General Punctuation – Windows 1252 [2026..2026]
Info(prcgen): Found UNICODE range: Latin-1 Supplement [A0..FF]
Info(prcgen): Building MOBI file, record count: 0001927
Info(prcgen): Compiling HTML Parser restart information
Info(prcgen): Final stats – text compressed to (in % of original size): 038.49%
Info(prcgen): The document identifier is: “PowerShell_Help”
Info(prcgen): The file format version is V6
Info(prcgen): Saving MOBI file
Info(prcgen): MOBI File successfully generated!
And the file is there:
Dropbox:\PowerShell\Scripts\Help2Kindle\PowerShellP> ls *.mobi
Mode LastWriteTime Length Name
—- ————- —— —-
-a— 6.1.11 11:59 PM 4598551 PowerShellP.mobi
Some notes
- I manually modified some HTML files. There were missing some tag’s parameters and KindleGen generated warning. It was not critical but I wanted nice output just with info messages.
- I found out that (in my opinion) is not necessary to create chapters/sections with deep nesting. Maybe – as the only exception – is the toc.html file itself where it should be useful to see the structure. But I decided that it’s not that important for me.
- You need to put ordered file names into <spin> tag in OPF file. Otherwise you content will be sorted by file name which is not so useful.
- Use Sample folder as a starting point. It’s pretty well described.
- Cover image size should be 800×600.
That’s enough of theory for now. Today we didn’t play with PowerShell so much so next time I’ll dedicate whole post to techniques I used during whole process (generating of files, TOC order, etc.)
PowerShell help on Kindle
Jan 5th
I bought my Kindle few months ago. As I am reading whole day during every possible break I have the Kindle still with me. Last week I was checking new book from Don Jones – Learn Windows PowerShell in a Month of Lunches. As I ordered it in MEAP I like Kindle feature to add my own notes “directly” to the book. What I am missing – is PowerShell
So I decided to move help files to Kindle to be able check anything I need.
Amazon provides command line tool named KindleGen and I recommend you to download it together with Kindle Previewer (both located at Amazon Kindle’s Publishing Program page). With KindleGen you’ll receive also two samples so you can find how it works.
As a source I used CHM file provided with PowerShell (you can access it from ISE by pressing F1 key).
I simply extracted HTML files from that file (by running hh.exe –decompile hlp c:\windows\help\WindowsPowerShellHelp.chm) and then process those files with KindleGen. As a result I received nice MOBI file
You can download the result from this location.
As this was really funny work and whole process of the file creation is not described anywhere (AFAIK) I plan some blog posts in the near future to show how to work with KindleGen itself and also to show how I used PowerShell to help me with some conversion/copy&pasting/generating XHTML.
Please note that my influence to this book was only the conversion from CHM to MOBI. All the texts inside were created by people from PowerShell team (except to Preface – I added it just for clarification) and all kudos needs to be send to Redmond.
