February 2010 - Posts

PowerShell in Practice – February update

The book is over half way through the author review process. This means that the editor has corrected my English and the technical reviewer has made his comments and I get to read all of this and revise as necessary.

Soon be done at this rate

Technorati Tags: ,
Posted by RichardSiddaway | with no comments

User Group on Tuesday

Don’t forget the User group Live Meeting on Tuesday 2 March at 7.30 GMT.

Details from http://msmvps.com/blogs/richardsiddaway/archive/2010/02/13/ug-meeting-2-march-2010.aspx

Technorati Tags: ,
Posted by RichardSiddaway | with no comments

Last Hotfix Install date

I was thinking about testing machines for when they were last patched and remembered that Get-Hotfix displays the Installed date for patches.  Unfortunately, it isn’t available for all patches so we can’t get a guaranteed last date of patching by this method.  However, we do get something close and if the script shows a date 3, 6 or worse months in the past we know we have some work to do.

001
002
003
004
005
006
007
".", "rslaptop01", "127.0.0.1" | foreach { 
    Get-HotFix -ComputerName $_  | 
    Where {$_.InstalledOn} | 
    sort InstalledOn -Descending | 
    select CSname, @{Name="Installed"; 
    Expression={"{0:dd MMMM yyyy}" -f [datetime]$_.InstalledOn.Tostring()}} -First 1
}

The script starts with a list of computers – for a longer list I would use a text file read by get-content.

This is piped into get-hotfix where we use the computer name parameter to pull the data from the machine of interest.

Where-Object is used to filter those results that have the InstalledOn date defined.  Then we sort on the date in a descending manner – latest first. A final select pulls off the machine name (CSname) and the last installed date.

On slight drawback to this is that the date is presented as MM\DD\YYYYY.  This becomes confusing for us folks that use DD\MM\YYYY.  To make it understandable by everyone I’ve converted the date format so the month is spelled out.  What is reported as 02/10/2010 becomes 10 February 2010.

 

Technorati Tags: ,,

PowerShell pack: Mount-SpecialFolder

Special folders are things like Favourites, Desktop and StartMenu folders.  The Mount-SpecialFolder mounts one specified special folder or all special folders.  The folders involved can be found by using the .NET enumeration used to discover them.

PS>  [Enum]::GetValues([Environment+SpecialFolder])
Desktop
Programs
Personal
Personal
Favorites
Startup
Recent
SendTo
StartMenu
MyMusic
DesktopDirectory
MyComputer
Templates
ApplicationData
LocalApplicationData
InternetCache
Cookies
History
CommonApplicationData
System
ProgramFiles
MyPictures
CommonProgramFiles

There are some special folders missing for instance the recycle bin.  The folders can be mounted by importing the Filesystem module and using the Mount-SpecialFolder function.  Supply a folder name and it is mounted as a PowerShell drive.  Just use the function name and all special folders are mounted.

Posted by RichardSiddaway | with no comments

PowerShell pack: Get-FreeDiskSpace

The Filesystem module has some interesting things for us.  The get-freediskspace function looked useful – so I tried it. It is safe so you can try this at home

PS> Get-FreeDiskSpace

Timestamp                 CounterSamples
---------                 --------------
25/02/2010 22:13:44       \\rslaptop01\logicaldisk(harddiskvolume1)\% free space :
                          71.7171717171717

                          \\rslaptop01\logicaldisk(c:)\% free space :
                          64.7910448672172

                          \\rslaptop01\logicaldisk(d:)\% free space :
                          85.3700423978962

                          \\rslaptop01\logicaldisk(g:)\% free space :
                          60.9804902451226

                          \\rslaptop01\logicaldisk(_total)\% free space :
                          71.1405628168288

                          \\rslaptop01\logicaldisk(harddiskvolume1)\free megabytes :
                          71

                          \\rslaptop01\logicaldisk(c:)\free megabytes :
                          106153

                          \\rslaptop01\logicaldisk(d:)\free megabytes :
                          63628

                          \\rslaptop01\logicaldisk(g:)\free megabytes :
                          1219

                          \\rslaptop01\logicaldisk(_total)\free megabytes :
                          171071

 

I’ve seen, and written, a few utilities to get free disk space.  This one is different because it uses performance counters. It shows the free space as a % and in megabytes.  As an example of how to use counters its worth examining the code using:

(get-command Get-FreeDiskSpace).Definition

 

I wanted to compare this to the information given by get-psdrive which displays the used and free space for drives. I was surprised to see a whole list of drives I wasn’t expecting including:

MyComputer
MyMusic
MyPictures
Personal
Program...
Programs
Recent
SendTo
StartMenu
Startup
System
Templates
Variable

 

A quick look at the module code shows that it runs the Mount-SpecialFolder function after loading the module.  Umm – that is a bit naughty I think – I don’t like configuration changes like this sneaking in.  Next time we’ll have a look at the mount-specialfolder function.

Posted by RichardSiddaway | with no comments

Windows PowerShell Community Review

 

Have you ever read Help that wasn't really helpful? Here's your chance to fix it.

The Windows PowerShell documentation team and PowerShellCommunity.org jointly sponsor the Windows PowerShell Community Doc Review. As a member, you'll get to read and comment on the Help docs before they're published, and work with the writers, editors, and the product team to make sure every word is really helpful.

We're looking for users at all experience levels and with all different backgrounds, but we love to have beginners, people with no programming experience, people who know other scripting languages or shells, and people who are not native English speakers. If you're a system admin and you don't really know Windows PowerShell, this is a great way to learn it with help from insiders.

Ready to rock the help? Contact June Blender (juneb@microsoft.com) or Marco Shaw (marco.shaw@gmail.com).

Posted by RichardSiddaway | with no comments
Filed under:

PowerShell pack: New-Zip

If all you want is an empty zip file for future use then import the filesystem module from the powershell pack and use

New-Zip -Path test3.zip

 

In case you were wondering copy-tozip uses it in the background when it creates a zip file

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

PowershellPack: copy-tozip

The PowerShell pack is part of the Windows 7 resource kit and is also available as a separate download.  The Filesystem module contains the following functions:

Copy-ToZip
Get-DuplicateFile
Get-FreeDiskSpace
Get-SHA1
Mount-SpecialFolder
New-Zip
Rename-Drive
Resolve-ShortcutFile
Start-FileSystemWatcher

 

Copy-ToZip does what it says and copies files into a .zip archive.  If the archive doesn’t exist it will create the archive.  To copy all the files in a directory

Get-ChildItem -Exclude *.zip | where{!$_.PSIsContainer} | Copy-ToZip -ZipFile test.zip

I just want the files so use where to filter out subfolders.  I exclude the zip file itself otherwise an error is generated. Copy-toZip has a –HideProgress parameter that hides the progress bar if required.

The function doesn’t provide the functionality of a fully fledged zip utility but for zipping up a bunch of files its good.  Easy to use in a script as well.

Posted by RichardSiddaway | with no comments
Filed under: ,

Community

I came across this post http://blogs.msdn.com/dtjones/archive/2010/01/06/what-makes-a-strong-community.aspx that talks about the SQL Server community – if you replace SQL Server with PowerShell I think the post is even more valid.

According to the post the two things that make a strong community are:

  1. the ability to get questions answered – quickly and with quality answers
  2. the welcoming of newcomers

For the PowerShell community I would add the support and openness of the PowerShell team –for instance compare the amount of information we get compared to some other products.

We still need to keep working on 1 & 2 above to make sure we stay a strong community.

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

Secure Strings

Secure Strings are a way to work with encrypted data – one of the common uses is to protect passwords used in scripts.  The way to use them may not be obvious at first sight.  I hope to clear some of the confusion around them in this post.

A common technique when asking for a password is to use Read-Host as follows

PS> $password = Read-Host "Pasword" -AsSecureString
Pasword: *********

 

The password you type is not displayed on screen.  If you examine $password we get this

PS> $password
System.Security.SecureString

 

PS> $password | gm

   TypeName: System.Security.SecureString

Name         MemberType Definition
----         ---------- ----------
AppendChar   Method     System.Void AppendChar(char c)
Clear        Method     System.Void Clear()
Copy         Method     System.Security.SecureString Copy()
Dispose      Method     System.Void Dispose()
Equals       Method     bool Equals(System.Object obj)
GetHashCode  Method     int GetHashCode()
GetType      Method     type GetType()
InsertAt     Method     System.Void InsertAt(int index, char c)
IsReadOnly   Method     bool IsReadOnly()
MakeReadOnly Method     System.Void MakeReadOnly()
RemoveAt     Method     System.Void RemoveAt(int index)
SetAt        Method     System.Void SetAt(int index, char c)
ToString     Method     string ToString()
Length       Property   System.Int32 Length {get;}

 

According to the .NET documentation

Represents text that should be kept confidential. The text is encrypted for privacy when being used, and deleted from computer memory when no longer needed. This class cannot be inherited.

 

We can also get to this point in another way

$password2 = ConvertTo-SecureString  -String "Password1"  -AsPlainText -Force

 

One draw back to secure strings is that we can’t save them in a file.  To do that we need to convert our secure string to an encrypted string using ConvertFrom-SecureString. We some options around the way we encrypt the string as the help file states:

If an encryption key is specified by using the Key or SecureKey parameters, the Rijndael encryption algorithm is used. The specified key must have a length of 128, 192, or 256 bits because those are the key lengths supported by the Rijndael encryption algorithm. If no key is specified, the Windows Data Protection API (DPAPI) is used to encrypt the standard string representation.

PS> $encrypted = ConvertFrom-SecureString -SecureString $password
PS> $encrypted
01000000d08c9ddf0115d1118c7a00c04fc297eb010000001a0fef9547d2e843afa025568a159d2f000000000200000000001066000000010000200
00000377a37eb27c57206a2c73a68fc9c4cad477420a354d9812706e16a836a3a0a4c000000000e80000000020000200000000ce7e56d09c6d1f741
f5ae5f523a2fbd1f9cf001dac56c969e0720f5d7f7c47a20000000914d09c3b241989227b050ab3d8b80b8cb66c13deffb70d6fe159423069ea9f04
000000092aa705254309565d6a0b55c68bfdd4079be1697f549333af9846f9e00438fba406a7e3f5ac77df8a20aa86bf6dbe8283b2ee9e1feb24d17
e37660eb2854dda6

 

We can save our encrypted string directly to disk

ConvertFrom-SecureString -SecureString $password | Set-Content encrypted.txt

and view the contents by

Get-Content encrypted.txt

If we want to get our secure string back from disk

$secured = ConvertTo-SecureString -String $(Get-Content encrypted.txt)

 

If you do decide to use the Key or SecureKey parameters when encrypting\decrypting secure strings make sure you remember the key!!

 

Having got our secure string we need to use either to supply credentials or to use the password in another program

If we want to create a credential object to use with a PowerShell cmdlet for instance

 

PS> $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "userid", $secured

PS> $cred | ft -a

UserName                     Password
--------                     --------
userid   System.Security.SecureString

 

If we need to use the password as plain text e.g. when setting an AD password or passing it into a command line utility that expects a plain text password we can access the password by using

PS> $cred.GetNetworkCredential().Password
Password1

 

Secure strings are useful to help key passwords and other sensitive data secure but we just need to be careful in how we use them.

 

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

PSCX: get-opticaldriveinfo

This useful for showing the supported formats

001
002
003
004
005
006
$drives = Get-OpticalDriveInfo
foreach ($drive in $drives) {
    $drive | Format-List MountPoint, VendorId, ProductId, ProductRevision 
    "Supported Profiles"
    $drive | select -ExpandProperty SupportedProfiles | foreach {" $_"}
}

 

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

SQL Server backup

An article I wrote for Windows Administration in Realtime has been posted on the Realtime Publishers tech tips site

 http://nexus.realtimepublishers.com/tips.php

then look for

Solidifying Your Backup and Recovery Srategy for SQl Server

It shows an example of using PowerShell to backup databases

Technorati Tags: ,
Posted by RichardSiddaway | with no comments

PSCX functions

As well as a set of cmdlets – version 2 of PSCX delivers an interesting set of functions

PS> Get-Command -Module pscx -CommandType function | format-wide -Column 3

Add-DirectoryLength                     Add-ShortPath                           cd-
cd..                                    cd...                                   cd....
cd.....                                 cd\                                     cd~
cd+                                     Dismount-VHD                            Edit-File
Edit-HostProfile                        Edit-Profile                            Enable-OpenPowerShellHere
Get-ChildItem                           Get-Help                                Get-PropertyValue
Get-PscxAlias                           Get-PscxCmdlet                          Get-PscxDrive
Get-PscxFunction                        Get-PscxProvider                        Get-ScreenCss
Get-ScreenHtml                          Get-ViewDefinition                      Invoke-BatchFile
Invoke-Elevated                         Invoke-GC                               Invoke-NullCoalescing
Invoke-Ternary                          less                                    Mount-VHD
New-HashObject                          Out-Speech                              Quote-List
Quote-String                            Resolve-ErrorRecord                     Resolve-HResult
Resolve-WindowsError                    Set-LocationEx                          Set-ReadOnly
Set-Writable                            Stop-RemoteProcess

 

Edit-Profile   will open your profile in Notepad 

Edit-File sw.txt – opens the sw.txt file in Notepad

invoke-elevated – opens a new PowerShell instance that has elevated privileges i.e. run as administrator

 

We’ll look at more of these functions as we progress through this series

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

Access: Invoke Stored procedure

 

After creating a stored procedure we need to be able to run it

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
function Invoke-AccessStoredProcedure {
# .ExternalHelp Maml-AccessFunctions.XML
[CmdletBinding()]
param (
    [System.Data.OleDb.OleDbConnection]$connection,
    [string]$name,
    [switch]$grid
)
    $sql = "EXECUTE $name "
    $cmd = New-Object System.Data.OleDb.OleDbCommand($sql, $connection)
    $reader = $cmd.ExecuteReader()
   
    $dt = New-Object System.Data.DataTable
    $dt.Load($reader)
   
    if ($grid) {$dt | Out-GridView -Title "$sql" }
    else {$dt}
}

 

All we need is the connection and the name of the procedure.  Our SQL command is EXECUTE and then we use similar code to reading the table directly. 

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

Hyper-V PowerShell library

James has announced an update to his PowerShell Hyper-V library.  http://blogs.technet.com/jamesone/archive/2010/02/15/powershell-and-hyperv.aspx

 

download it from

http://pshyperv.codeplex.com/releases/view/38769

 

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

PowerShell in Practice deal

Manning are running a Deal of the Day Sunday 14 February for PowerShell in Practice

 

The deal is $15 for the ebook version.  Follow the link from http://www.manning.com/ and use discount code dotd0214

 

Please fell free to communicate to anyone you think may be interested

 

Enjoy

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

Access: Stored Procedure

Next stop on our trip around Access functionality is the stored procedure.  An SP is a piece of code that we have defined, and saved in the database. It may take parameters or may just be a straight select statement.

As with any Access object we have to start with creation

001
002
003
004
005
006
007
008
009
010
011
012
013
014
function New-AccessStoredProcedure {
# .ExternalHelp Maml-AccessFunctions.XML
[CmdletBinding()]
param (
    [System.Data.OleDb.OleDbConnection]$connection,
    [string]$name,
    [string]$proc
)
    $sql = "CREATE PROCEDURE $name AS $proc"
    Write-Debug $sql
   
    $cmd = New-Object System.Data.OleDb.OleDbCommand($sql, $connection)
    $cmd.ExecuteNonQuery()   
}

 

As before we’ll build up the function.  We start with a simple procedure where we give the connection, a procedure name and the SQL statement for the procedure.

The function is used like this:

PS> Import-Module accessfunctions -Force
PS> $db = Open-AccessDatabase -name test03.mdb -path c:\test
PS> New-AccessStoredProcedure -connection $db -name "proc1" -proc "select * from test1"
0
PS> Close-AccessDatabase $db

Next time we will see how to use a stored procedure in our PowerShell code

 

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

UG Meeting 2 March 2010


When: Tuesday, Mar 2, 2010 7:30 PM (GMT)


Where: Virtual

*~*~*~*~*~*~*~*~*~*

Session will cover PowerShell v2 on Windows 7 and the default functionality. We will also look at the PowerShell functionality delivered in the Windows 7 Resource Kit.

Notes


Richard Siddaway has invited you to attend an online meeting using Live Meeting.
Join the meeting.
Audio Information
Computer Audio
To use computer audio, you need speakers and microphone, or a headset.
First Time Users:
To save time before the meeting, check your system to make sure it is ready to use Microsoft Office Live Meeting.
Troubleshooting
Unable to join the meeting? Follow these steps:

  1. Copy this address and paste it into your web browser:
    https://www.livemeeting.com/cc/usergroups/join
  2. Copy and paste the required information:
    Meeting ID: C6F282
    Entry Code: tj|G4%&`8
    Location: https://www.livemeeting.com/cc/usergroups

If you still cannot enter the meeting, contact support

Notice
Microsoft Office Live Meeting can be used to record meetings. By participating in this meeting, you agree that your communications may be monitored or recorded at any time during the meeting.

Technorati Tags: ,

Execution Policies

By default PowerShell can’t run scripts when first installed because the execution policy is set to Restricted.  Lee Holmes has put a good explanation of some of the thinking around execution policies and what should be done about them - http://blogs.msdn.com/powershell/archive/2010/02/12/building-on-powershell-execution-policies.aspx

 

For more information see page 551 of Ed Wilson’s new book - Windows PowerShell 2.0 Best Practices – which I will be reviewing soon. 

 

Posted by RichardSiddaway | with no comments
Filed under:

PSCX: Set-VolumeLabel

Need to change a volume label.  It couldn’t be easier.

Set-VolumeLabel -Path g:\ -Label "Heroes"

Will change the label of the g: drive.

PSCX doesn’t supply a cmdlet to read volume labels.  But we can get round that with a bit of WMI

001
002
003
004
005
006
007
008
009
010
011
012
function Get-VolumeLabel {
param ([string]$computer=".",
       [string]$drive = $null
)
    if ($drive){
        if ($drive -notlike "?:"){ Throw "Drive should be submitted as letter and colon e.g. C:"}
        $wmiq = Get-WmiObject -Class Win32_LogicalDisk -Filter "DeviceId='$($drive)'" -Computer $computer
    }
    else {$wmiq = Get-WmiObject -Class Win32_LogicalDisk -Computer $computer}
   
    $wmiq | select DeviceId, VolumeName
}

 

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