Categories

Monthly Archives: February 2010

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: ,

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: ,

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.

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.

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).

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: ,

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.

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: ,

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: ,