Thursday, March 26, 2009

PowerShell f’in rocks!

Here’s my first love letter…

  • Main Microsoft landing page for PowerShell… download and install it!!  (if you’re running Windows Server 2008, it’s already loaded)
  • Out of the box things are locked down for security… there’s a couple immediate tasks…
    • Go find the PowerShell icon and fire it up…
    • Turn on ability to run PowerShell script files via
      Set-ExecutionPolicy RemoteSigned” … you’ll need to do this right up front (only once) since this is locked down by default
    • Download and install the PowerShell Community Extensions (PSCX)… all kinds of baseline goodies
    • The PSCX install will establish a default “profile.ps1” script that establishes a bunch of handy default shell and script functionality
    • Profile.ps1 lives here: “%USERPROFILE%\My Documents\WindowsPowerShell\Profile.ps1” (don’t worry, Vista maps “My Documents” to the appropriate new physical folder for backwards compatibility with XP)
  • We get full access to everything in the .Net Framework from a friendly script syntax… there’s already a gaggle of PowerShell wrappers (aka “cmdlets”) that hide the uglier details of accessing Windows Registry, Web Services, XML, WMI, Active Directory, Exchange Server, SQL Server Admin, SharePoint… on and on
  • Cmdlets are just more scripting (plus .Net “snapin” DLLs where needed) so folks are actively simplifying access to all available technologies with more and more publicly available cmdlet libraries all the time.
  • Windows Forms via PowerShell is pretty cool… PowerShell’s script is a pretty easy flowing syntax and has loads of friendly libraries available to do all the heavy lifting… marry that with .Net Forms GUIs and you can get some nifty stuff rolling in a day…
  • See my first script below… it does a nice batch of meat and potatoes ditch work in about 75 short lines of fairly readable code
  • Invoke-Win32” - The smarties have already built an awesome “function which uses code generation to dynamically create a .Net P/Invoke definition” so that we can fire Win32 API’s on a whim! Copy/Paste the definition of the Invoke-Win32 function into your Profile.ps1 right after the other functions defined in there
  • Hide-PowerShell() – (code tweaked a bit below) very handy for hiding the PowerShell console when all you really want to see is the Window Forms stuff you threw together… just toss this short code into your Profile.ps1 as well
  • PowerShellPlus – very nice IDE with gonzo Intellisense & context Help for E-VER-Y-THING in da Shell… love it… running 2.1.0.45 Beta, hasn’t crashed once

My First PowerShell Script – awww aint she a cutie

Hits SQL Server to pull a list of remote office PC’s data via the ol’ ADO.Net APIs we know by heart, pings all those machines to determine if they’re online (currently commented out but it runs quite fast), then throws the list into a simple Windows Forms ListBox for user selection and finally sets a registry entry (an ODBC System DSN Server entry) based on the chosen selection & launches a full blown app… this little ditty is a front end for something that belongs in the main app but that’s all in VB6 so i didn’t want to go there :)…

<begin code>

Hide-PowerShell

$cn = new-object system.data.SqlClient.SqlConnection("Data Source=blah;User ID=blah;Password=blah");
$ds = new-object "System.Data.DataSet" "dsTaxOffices"
$q = "SELECT Name + ' ('+Code+')' as Name, IPAddress FROM master.dbo.TaxOffices (nolock) where Active = 1"
$da = new-object "System.Data.SqlClient.SqlDataAdapter" ($q, $cn)
$da.Fill($ds)

# ping each box to see who's online
#foreach($row in $ds.Tables[0].Rows) {
# $ipaddress = $row["IPAddress"]
# $ping_result = Get-WmiObject -Class Win32_PingStatus -Filter "Address='$ipaddress'"
# if ($ping_result.StatusCode -ne "0") {
# $row["Name"] = $row["Name"] + "`t* offline *"
# }
#}

# Load Windows Forms Library
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null

#pointer for easy debug message box popups
$mb=[Windows.Forms.MessageBox]
#$mb::Show("you clicked me! ", "Message")

# Create Window
$form = new-object "System.Windows.Forms.Form"
$form.Size = new-object System.Drawing.Size @(300,377)
$form.topmost = $true
$form.text = "Choose Office"
$form.FormBorderStyle = "FixedToolWindow"
#$form.add_load({
#$mb::Show("onload", "onload")
# $form.WindowState = "Normal"
#})

# Create Flow Panel
#$panel = new-object "System.Windows.Forms.flowlayoutpanel"
#$panel.Dock = [System.Windows.Forms.DockStyle]::Fill
#$form.Controls.Add($panel)

# Create Controls
$lst = new-object System.Windows.Forms.ListBox
#$lst.FormattingEnabled = true;
#$lst.TabIndex = 0;
$lst.Location = new System.Drawing.Point(3, 3);
$lst.Name = "listBox1";
$lst.Size = New-Object System.Drawing.Size @(285, 320);

# databind list of offices to listbox
$lst.ValueMember = "IPAddress"
$lst.DisplayMember = "Name"
$lst.DataSource = $ds.Tables[0]

$btnSelect = New-Object System.Windows.Forms.Button
$btnSelect.Location = New-Object System.Drawing.Point @(65, 325)
$btnSelect.Name = "button1";
$btnSelect.Size = New-Object System.Drawing.Size @(159, 23);
#$btnSelect.TabIndex = 1;
$btnSelect.Text = "Select";
#$btnSelect.UseVisualStyleBackColor = true;
$form.AcceptButton = $btnSelect

$btnSelect.add_click({
Set-ItemProperty hklm:\software\odbc\odbc.ini\itraac Server $lst.SelectedItem.IPAddress
Get-Process | Where-Object {$_.Name -eq "itraacw32"} | kill
sleep 1 #wait a sec for the old process to really drop off, otherwise new one collides and stops itself
start "C:\Program Files\iTRAAC Console\iTRAACw32.exe"
$form.Close()
})

# Add controls to Panel
$form.Controls.Add($lst)
$form.Controls.Add($btnSelect)

# Show window
$form.showdialog()




Everybody needs a picture right?



image



Hide-PowerShell() script source



function ShowWindowAsync([IntPtr] $hWnd, [Int32] $nCmdShow)
{
$parameterTypes = [IntPtr], [Int32]
$parameters = $hWnd, $nCmdShow
Invoke-Win32 "user32.dll" ([Boolean]) "ShowWindowAsync" $parameterTypes $parameters

# Values for $nCmdShow
# SW_HIDE = 0;
# SW_SHOWNORMAL = 1;
# SW_NORMAL = 1;
# SW_SHOWMINIMIZED = 2;
# SW_SHOWMAXIMIZED = 3;
# SW_MAXIMIZE = 3;
# SW_SHOWNOACTIVATE = 4;
# SW_SHOW = 5;
# SW_MINIMIZE = 6;
# SW_SHOWMINNOACTIVE = 7;
# SW_SHOWNA = 8;
# SW_RESTORE = 9;
# SW_SHOWDEFAULT = 10;
# SW_MAX = 10
}
function Show-PowerShell() {
$null = ShowWindowAsync (Get-Process -Id $pid).MainWindowHandle 1
}
function Hide-PowerShell() {
$null = ShowWindowAsync (Get-Process -Id $pid).MainWindowHandle 0
}
function Minimize-PowerShell() {
$null = ShowWindowAsync (Get-Process -Id $pid).MainWindowHandle 2
}

0 comments: