August 2009 - Posts

PowerShell v2 help file

In PowerShell v2 we get a nice graphical help system that includes the cmdlets, the about files and and the User and Getting Started Guide. It doesn’t include the help for the optional modules though which is a pity.

The default locations on the Start Menu for PowerShell are Accessories – Windows PowerShell.  That is not very good placement considering Windows only really exists to give us somewhere to run Powershell :-)  

In these locations the help files are not visible. If you open up ISE then you can access the help file.

If you pin PowerShell to the start menu on Windows 7 then you get access to the help through the recent files menu.  The help file is located (on my system) at C:\Windows\Help\mui\0409\WindowsPowerShellHelp.chm

I keep a shortcut on my desktop and a shortcut to the version 1 graphical help file from the script center.  that way I can compare changes.

Technorati Tags: ,
Posted by RichardSiddaway | 1 comment(s)
Filed under:

Word Add a table

There seems to be two types of paragraph I create in Word documents – text or tables.  Lets start by adding a table.

001
002
003
004
005
006
007
008
009
function Add-Table {
    param (
        [int] $row = 2,
        [int] $col = 5
    )
    $global:paragraph = $doc.Content.Paragraphs.Add()
    $range = $paragraph.Range
    $global:table = $doc.Tables.Add($range,$row,$col)
}

 

The function Add-Table takes two integers as parameters. They define the rows and columns of the table.  The way that seems to work best is to add a paragraph to contain the table and then add the table into the paragraph.  If we just add the table to the document it overwrites the contents of the document with the table. oops.

Notice that I’m using global variables again so that they can be used across the environment.

Next time we will add some data to the table.

Technorati Tags: ,,,
Posted by RichardSiddaway | with no comments
Filed under:

Enable Ping

I’ve got a few talks coming up so need to build some more demo machines.  One thing I like to be able to do in the demo environment is ping between machines – sometimes necessary when testing things out but ping is disabled by the Windows firewall in Windows 2008 & R2.

James O’Neill has blogged about working with the Windows firewall at http://blogs.technet.com/jamesone/archive/2009/02/18/how-to-manage-the-windows-firewall-settings-with-powershell.aspx

To just set ping on

001
002
003
004
005
006
007
008
009
$fw = New-Object -ComObject HNetCfg.FWPolicy2
#$fw.Rules | Format-Table Name, Enabled, Direction -AutoSize

$fw.Rules | where {$_.Name -like "File and Printer Sharing (Echo Request - ICMPv4-In)"} | 
foreach {$_.Enabled = $true}

$fw.Rules | where {$_.Name -like "File and Printer Sharing (Echo Request - ICMPv4-In)"} | 
Format-Table Name, Direction, Protocol, Profiles, Enabled -AutoSize

Use the HNetCfg.FWPolicy2  COM object  and enable the rules for "File and Printer Sharing (Echo Request - ICMPv4-In)".  There are similar rules for IPv6 if needed.  Blocking pings is just the opposite.

Technorati Tags: ,,
Posted by RichardSiddaway | with no comments
Filed under:

Module path

PowerShell v2 has 2 default locations for modules – in the install directory and in your profile.  My demo laptop is set to dual boot Windows 7 & Windows 2008 R2.  It would make sense to only maintain one set of files for the modules I write. There is a PowerShell automatic variable that sets where PowerShell looks for modules.  To add my own folder to that path I just add

$env:PSModulePath = "C:\Scripts\Modules;" + $env:PSModulePath

to my profile.  The modules will be available now from either machine.  Need to change drive letter in the Win 2008 profile but otherwise just the same.

Technorati Tags: ,
Posted by RichardSiddaway | with no comments

Word New Document change

I started experimenting with the New-WordDocument function and realised I needed to change it to make the variables usable across the functions.

001
002
003
004
005
function New-WordDocument {
    $global:word = New-Object -ComObject Word.Application
    $word.Visible = $true
    $global:doc = $Word.Documents.Add() 
}

 

Simple change is to make the variables global in scope.  This means they are available across the functions of the module and form with scripts and from the prompt.

Depending on what you want to do you may not need this change but as I want to eventually use the module functions from scripts it works for me.

Posted by RichardSiddaway | with no comments
Filed under:

Word New Document

Lets add another function to our module for working with Word.  Its time to create a new word document

001
002
003
004
005
function New-WordDocument {
    $word = New-Object -ComObject Word.Application
    $word.Visible = $true
    $Word.Documents.Add() | Out-Null
}

 

Create the object for word as before.  Set the visible property to true (we can’t use it if we can’t see it)  We then add a document.  The Out-Null I found was necessary on my Windows 7 & Office 2010 combination because a lot of stuff was generated that I didn’t want to see.  Try it without on other combinations.  I don’t remember it being so bad with Word 2007

Posted by RichardSiddaway | with no comments
Filed under:

Word Autocorrect

If you have been following this blog for awhile you will know that I build and rebuild machines on a reasonably frequent basis.  One drawback to this that I have to keep re-creating the Autocorrect entries.  I do a lot of technical writing much of which involves full names of products and correct capitalisation.  I saw an entry on the TechNet scripting center that showed how to add an entry to the autocorrect list.  It was in VBScript but thats not an issue as we can easily convert it to something more useful  :-)

I ended up with a module consisting of four functions

  • Get-AutoCorrectEntry
  • Export-AutoCorrectEntry
  • Add-AutoCorrectEntry
  • Import-AutoCorrectEntry

 

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
#Requires -version 2.0
function Get-AutoCorrectEntry {
    param (
        [switch] $all
    )
    $word = New-Object -ComObject Word.Application
    if ($all) {$word.AutoCorrect.Entries}
    else {$word.AutoCorrect.Entries | Select Name, Value}
    $word.Quit()
}
function Export-AutoCorrectEntry {
    param (
        [parameter(Mandatory=$true)]
        [string] $path
    )
   
    Get-AutoCorrectEntry | where {$_.Value -ne "*"} | Export-Csv -Path $path -NoTypeInformation
}
function Add-AutoCorrectEntry {
    param (
        [parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
        [string] $name,
       
        [parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
        [string] $value
                      
    )
    begin {
        $word = New-Object -ComObject Word.Application
        $ace = $word.AutoCorrect.Entries
    }
    process {$ace.Add($name, $value)}
    end {$word.Quit()}
   
}
function Import-AutoCorrectEntry {
    param (
        [parameter(Mandatory=$true)]
        [string] $path
    )
    Import-Csv -Path $path | Add-AutoCorrectEntry

}

 

Get-AutoCorrectEntry creates an object for Word and dumps the contents of the AutoCorrect Entries collection.  Default is to just display the name and the value where name is the bad text and value is the replacement text.  The –all switch dumps everything but we won’t usually need that info

Export-AutoCorrectEntry calls Get-AutoCorrectEntry add dumps the results to a file using Export-Csv.  Using where {$_.Value -ne "*"} restricts the output to the entries I’ve created rather than including Word’s own entries

Add-AutoCorrectEntry creates a new entry.  It takes name and value parameters then creates an object for word, gets the AutoCorrect Entries then uses the Add method to create the new entry.  I’ve used the begin/process/end scriptblocks so it behaves nicely on the pipeline

Import-AutoCorrectEntry reads a csv file then calls Add-AutoCorrectEntry

Next time I re-install Office I can dump the entries and then import them after installation.  I can even move my entries between machines.  I created this using Windows 7 and Office 2010 TP but there is no reason for it not to work with other versions of Office.

 

Posted by RichardSiddaway | with no comments
Filed under:

File download problem

If you are using the Office 2010 TP and try to download a word document through Internet Explorer you end up in a continuous loop of being asked for credentials.  The download site won’t recognise your local credentials so you can’t get the documents.  You do however get to see the URL from where the document is coming.

So the answer to this conumdrum is to use the BITS file transfer cmdlets in Windows 7.

Start by importing the module

Import-Module BitsTransfer

You can then download the files

Start-BitsTransfer -Source http://download.microsoft.com/download/F/2/1/F2146213-4AC0-4C50-B69A-12428FF0B077/Windows_Server_2008_R2_Failover_Clustering_In_Brief.doc -Destination c:\source
Start-BitsTransfer -Source http://download.microsoft.com/download/F/2/1/F2146213-4AC0-4C50-B69A-12428FF0B077/WS08%20R2%20Failover%20Clustering%20White%20Paper.doc -Destination c:\source

Typing the URLs is a pain but at least we can now get the things downloaded.

Posted by RichardSiddaway | with no comments
Filed under:

TCP Ports

I came across this post http://www.expta.com/2009/08/name-that-port.html that gives the well known service for a TCP\UDP port.  Useful script but its written in VBScript.  Needs to be in PowerShell.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
param ([int]$port)
$data = @'
1 = TCP Port Service Multiplexer
2 = Management Utility
3 = Compression Process
4 = Unassigned

.... lots more in here

48003 = Nimbus Gateway
48556 = com-bardac-dw
'@

$ports = ConvertFrom-StringData -StringData $data

$ports["$port"]

 

Easy.  Create a script called get-port. It takes an integer as a port number. The ports and services are held in a here string and then ConvertFrom-StringData is used to create a hash table.

We then look up the port to get the service.   Next trick is to turn it round so that we can find the port number given the string.  I’ll add that next post and put the whole string on my skydrive as its too long to publish here

 

Technorati Tags: ,
Posted by RichardSiddaway | with no comments
Filed under:

Windows 2008 R2 RTM

It hasn’t had the same level of fanfares but Windows Server 2008 R2 RTM is available for download from TechNet\MSDN.  I’ll be converting my test domain over the next few days and reporting on all the PowerShell goodies we get

Posted by RichardSiddaway | with no comments
Filed under:

PowerShell v2

PowerShell v2 is available already in Windows 7 (and shortly in Win 2008 R2). A Release Candidate is now available for Vista\Windows 2008

https://connect.microsoft.com/windowsmanagement/Downloads

As explained http://blogs.msdn.com/powershell/archive/2009/08/14/powershell-2-0-for-windows-vista-and-windows-server-2008-release-candidate.aspx

it is a combined packages contain PowerShell v2, WinRM 2.0 and BITS 4.0

All you need except .NET.  You will need .NET 3.5 if you want to use out-gridview

XP and Win 2003 versions will follow

Posted by RichardSiddaway | with no comments

Blind Search

This is an interesting experiment - http://blindsearch.fejus.com/

Enter your search and get results back from bing, yahoo and google.  But you don’t know which is which.  Then choose which you think returned the best results.

Interesting results.

Technorati Tags:
Posted by RichardSiddaway | with no comments
Filed under:

System Up Time

The PowerShell team have just posted about obtaining system up time using a .NET class to convert the WMI date format to something thats readable

http://blogs.msdn.com/powershell/archive/2009/08/12/get-systemuptime-and-working-with-the-wmi-date-format.aspx

There is a WMI only way of doing this

$os = Get-WmiObject -Class Win32_OperatingSystem
$os.ConvertToDateTime($os.LastBootUpTime)

But this gives the date and time the system was last booted.  If you want the actual up time then use

(get-date) - $os.ConvertToDateTime($os.LastBootUpTime)

which generates a timespan object

Days              : 0
Hours             : 1
Minutes           : 53
Seconds           : 8
Milliseconds      : 461
Ticks             : 67884618000
TotalDays         : 0.0785701597222222
TotalHours        : 1.88568383333333
TotalMinutes      : 113.14103
TotalSeconds      : 6788.4618
TotalMilliseconds : 6788461.8

which gives the actual up time.  The .NET method can be substituted for the WMI method if required

Technorati Tags: ,,

PowerShell 2 on Windows 7 - Remoting

One thing I noticed was that remoting appears to be switched on by default.  I did a clean install to the extent of deleting and resizing the install partition so it shouldn’t have picked up any remnants of previous installs.

The execution policy still defaults to restricted.

Technorati Tags: ,,
Posted by RichardSiddaway | with no comments
Filed under:

Windows 7 RTM first impressions

The machine is rebuilt and all applications re-installed.  I said after installing the RC as an upgrade that I felt some of the Vista feel had come across.  This install feels much better – like the beta that impressed me so much at the beginning of the year. 

I recommend a clean install for Windows 7 if at all possible.

I’ll have to try re-installing Win 7 on that old laptop and see how it does.  In theory it should run better than the beta.

First impressions – very impressed.  I like this.  Previous Windows clients have left me feeling so-so. They worked and did what I want but this feels right. The whole thing has a polish and well thought out togetherness that I don’t think has been there in the last few client OSs.

This is a winner.

Technorati Tags:
Posted by RichardSiddaway | with no comments
Filed under:

Windows 7 and PowerGUI 1.9

Currently rebuilding the laptop.  Downloaded Windows 7 RTM from TechNet last night and did a complete refresh.  PowerGUI is one of the first installs on any new machine. The latest version installs great.  Notice the opportunity to prevent the association of the editor with PowerShell files has been moved and is much more visible and accessible.

So far everything seems good.  I like the way that 1.9 picks up the installed modules – very neat

Technorati Tags: ,
Posted by RichardSiddaway | with no comments
Filed under:

Service loading

This isn’t quite finished but there is enough useful stuff to share.  I was wondering what order things are loaded – especially services and found that this information can be found in the registry – only difficulty is reading it.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
$data = @()
## create class for object
$source=@"
public class StartOrder
{
    private string _servicename;
    private string _displayname;
    private int _tag;
    private string _group;
    private int _grouporder;
    
     public string DisplayName {
        get {return _displayname;}
         set {_displayname = value;}
    }
    
    public string ServiceName {
        get {return _servicename;}
         set {_servicename = value;}
    }
    
    public string Group {
        get {return _group;}
         set {_group = value;}
    }
    
    public int Tag {
        get {return _tag;}
         set {_tag = value;}
    }

    public int GroupOrder {
        get {return _grouporder;}
         set {_grouporder = value;}
    }
}
"@

Add-Type -TypeDefinition $source

Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\Services | foreach {
    $so = New-Object -TypeName StartOrder
    $so.ServiceName = $_.PSChildName

    $i = Get-Item -Path $_.PSPath
    if ($i.Property -contains "DisplayName"){
        $dn = Get-ItemProperty -Path $_.PSPath -Name DisplayName
        $so.displayname = $dn.displayname
    }
    if ($i.Property -contains "Group"){
        $gp = Get-ItemProperty -Path $_.PSPath -Name Group
        $so.group = $gp.Group
    }
    if ($i.Property -contains "Tag"){
        $tag = Get-ItemProperty -Path $_.PSPath -Name Tag
        $so.tag = $tag.Tag
    }
    $data += $so
}
## now we set the group order
$gpo = @{}
$groups = (Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\ServiceGroupOrder -Name List).List
for ($i=0; $i -le $($groups.length-1); $i++){$gpo += @{$($groups[$i]) = $i}}

for ($i=0; $i -le $($data.length-1); $i++){
    if ($data[$i].Group -eq $null){$data[$i].GroupOrder = 255}
    else {$data[$i].GroupOrder = $gpo[$($data[$i].Group)]} 
   
    ## reset for service groups not is start list
    if ($data[$i].GroupOrder -eq 0){$data[$i].GroupOrder = 250}
   
    ## tidy display names
   
    if (($data[$i].DisplayName -eq $null) -or ($data[$i].DisplayName.StartsWith("@"))){
        $data[$i].DisplayName = (Get-Service $($data[$i].ServiceName) -ErrorAction SilentlyContinue ).DisplayName
    }

}
$data | sort grouporder, group, tag |  Out-GridView -Title "Service Start Order"
#$data | sort grouporder, tag | select -Propert DisplayName, ServiceName, Group, Tag -ExcludeProperty grouporder | Out-GridView -Title "Service Start Order"

 

We’ll start by creating an empty array and a new object class.  Basically all we are doing is defining a set of properties on the object.  Add-Type is then used to create the class.

We can read the services out of the registry at HKLM:\SYSTEM\CurrentControlSet\Services – note that this includes drivers as well as services. We can populate the properties of our object as we loop through the services. Name and DisplayName should be self explanatory. Group  indicates which group the service loads in – services in groups load before those that aren’t in groups. The tag indicates the relative load order within the group. Not all services have a group or tag which is why I test for them.

The list of groups in load order can found at HKLM:\SYSTEM\CurrentControlSet\Control\ServiceGroupOrder.  Loop through them and create a hash table with the name and load order. We loop through the services setting the group order property – this is a fudge to give me something to sort on – may be a better way but still working on it.  If there isn’t a group we get an order of 255 (arbitrary) to put it at the end.  If a group isn’t in the list set to 250 otherwise pick the load order from the hash table.

The DisplayName is always what we are used to so take the opportunity to reset with get-service.  The  -ErrorAction SilentlyContinue masks any error messages.

Finally sort the data and use out-gridview to display.

I want to add a few more properties but this is already quite useful. It will end up as another function in my services module

Technorati Tags: ,
Posted by RichardSiddaway | with no comments
Filed under:

AD User Group

September 16th I will be presenting to the AD User Group:

An "Introduction to Powershell"‬‪ ‬‪Windows 2008 R2 brings PowerShell v2 installed by default. It also brings a raft of PowerShell functionality including a provider and cmdlets for Active Directory. This session will introduce PowerShell for those new to it and show you how to use PowerShell v2 and the Microsoft cmdlets to administer your AD. We will also compare and contrast with AD tools currently available in PowerShell.

Sessions start at 6pm

Details from  http://adug0909.eventbrite.com

Technorati Tags: ,
Posted by RichardSiddaway | with no comments

Service Startup type

We can modify the service startup type by using WMI or with PowerShell v2 we can use set-service.  This has a number of other useful functions. Its just a matter of testing the type we want to change the startup to and applying it to the service.  This becomes another function in my services module.

001
002
003
004
005
function Set-StartupType {
param ([string]$name, [string]$type)
    if ("Automatic", "Manual", "Disabled" -contains $type) {Set-Service -Name $name -StartupType $type}
    else {Write-Host "Type must be Automatic, Manual or Disabled"}
}

 

You do need elevated privileges to change the startup type.

Technorati Tags: ,,,
Posted by RichardSiddaway | with no comments

Service Startup History

If we need to look at the startup history of a service we can find the information in the event log

 

001
002
003
004
005
006
function Get-ServiceStartupHistory {
param ([string]$name ) 

Get-EventLog -LogName System | where {(($_.EventId -eq 7035) -or ($_.EventId -eq 7036)) -and $_.Message -like "The $($name)*"}

}

 

I’ve done this as a function as I’m moving all my service based scripts into a module. Eventually, all my scripts will be in modules

Technorati Tags: ,,,
Posted by RichardSiddaway | with no comments
More Posts Next page »