Monthly Archives: April 2009

How many bytes?

I was playing around with PowerShell and started thinking about the kb, mb etc values and I realised I didn’t know what they really looked like.  1kb is 1024 but it gets very hazy after that. So how could I see the values stacked up

1kb,1mb,1gb,1tb,1pb | foreach{"$_".PadLeft(16)}

works.  We feed in the list of values. Pipe into foreach and use string substitution to display.  That will left justify the display.  By padding the left of the display with spaces we can effectively right justify the field to give

            1024
         1048576
      1073741824
   1099511627776
1125899906842624

So now you know what the stack of xbytes looks like

We can also achieve the same effect using

1kb,1mb,1gb,1tb,1pb | foreach{"{0,16}" -f $_}

Hmm.. wonder how effort is involved to produce a Tower of Hanoi script from this

Technorati Tags: ,,

Creating a process

I've looked at creating a process before - using [WMIClass].

 

With CTP3 we have a few more options

 

Start-Process -Filepath notepad.exe

 

Invoke-WMIMethod -Class Win32_process -Name Create -ArgumentList notepad.exe

 

Set-WMIinstance -Class Win32_process -Arguments @{Path=c:\windows\system32\notepad.exe}

 

The first two just happen.  The third option will throw an exception because it can't find the instance and then create one.

 

Three options - which to use.  In this case probably start-process but the invoke-wmimethod is useful.

PowerShell verbs

If you haven't seen the post on PowerShell standard verbs from the PowerShell team it is worth reading - http://blogs.msdn.com/powershell/archive/2009/04/22/soliciting-new-verbs.aspx

 

If you have an idea for a new verb - make sure you make it known

PowerShell remoting options

One of the big pieces of functionality in PowerShell v2 is the ability to directly administer remote machines.  A number of cmdlets get a computername parameter for working directly. The main push for remoting is through the *-PSsession cmdlets

Enter-PSSession
Exit-PSSession
Export-PSSession
Get-PSSession
Import-PSSession
New-PSSession
Remove-PSSession

New-, Get and Remove- I have blogged about before.  The interesting ones are the Enter/Exit and Import/Export pairs.

Enter-PSsession enables you to work directly in the session – as if you had RDP’d into the machine and were running PowerShell on the box.  It means we don’t need to use Invoke-Command as much. Exit-PSsession steps back out of the session but leaves the session open.

Import-PSsession enables you to import functionality from the remote session into your local PowerShell session.  For instance you can import the 2008 R2 AD cmdlets into your local session.  They show up as functions rather than cmdlets but are fully usable.

Export-PSsession saves PowerShell command types (cmdlets, functions etc) to a module that can be loaded at any time into a session.

There is a lot of flexibility and power built into the remoting system that should allow you to get a way of working that suits you.

Technorati Tags: ,,

Too ambitious?

Been looking at Exchange 2010.  It installed OK on Windows 2008 R2 Beta and seemed to run OK.  I have come across a few issues:

  • Exchange Management Console doesn’t start properly and doesn’t run properly
  • The new Remote PowerShell functionality doesn’t work (against Windows 7)

I think this is due to trying to work two betas together.  I’m going to put Exchange 2010 onto Windows 2008 SP1 and see what happens when I use PowerShell CTP 3 against it.

Apart from the Exchange 2010 looks good.  The way Exchange 2010 uses PowerShell has changed significantly – especially for remote access.  Really makes remote PowerShell the way to go.

I hope that the RTM timings can be sorted so that Exchange 2010 RTM will work properly on Windows 2008 R2.  Be a big shame to have to wait for Ex 2010 SP1 for this combination.

 

Technorati Tags: ,,

AD attributes

I had a question come through as a private message regarding how to extract a particular attribute for user objects. The script wasn’t working because the label name in AD Users and Computers didn’t match the attribute name. This is a fairly common scenario as there are quite a few attributes like this for instance in the GUI the label is First Name but the AD attribute that we need to access in our PowerShell scripts is givenName (capitalisation isn’t mandatory).

How can we find the correct attribute.  I tend to dive into ADSIEdit. I pick a test user. Set the value of the attribute in question to something obvious using the GUI then look it up in ADSIEdit.

Another way is to use the information on msdn - http://msdn.microsoft.com/en-us/ms677980(VS.85).aspx.  There is a set of User Object User Interface Mapping tables one for each tab in the GUI.

At http://msdn.microsoft.com/en-us/ms677286.aspx you can find a link that covers mapping for computers, domains, groups, OUs printers and users.

With this information easily available and much of it defined as parameters in the AD cmdlets (Win 2008R2 and Quest) accessing AD objects in scripts becomes much easier. 

Technorati Tags: ,

Sorting

Sorting is a fairly common activity in PowerShell.  One scenario I don’t see very often is a requirement to sort in two different directions.  I have a list of users and their last logon dates – I want to sort users into alphabetical order (ascending) and lat logon into descending order.

001
Import-Csv logons.txt | sort @{Expression="Name";Descending=$false},@{Expression="LastLogon";Descending=$true}

We have to use a hash table for the fields and the direction if we want different sorting directions.  Looks a bit messy but works a treat.

Technorati Tags: ,

User Module – local account

Back in February - http://richardsiddaway.spaces.live.com/blog/cns!43CFA46A74CF3E96!2099.entry – I showed a module I had created to generate a new password.  Its time to return to that module.  I am going to expand it to work with local user accounts. Then I’ll add AD accounts.

I have a script that I wrote a while back to work with local accounts

 

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
## To create a user on the local machine
## add the assembly
Add-Type -AssemblyName System.DirectoryServices.AccountManagement

## create a password
$password = Read-Host "Password" -AsSecureString
$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "userid", $password


## create the context i.e. connect to the domain
$ctype = [System.DirectoryServices.AccountManagement.ContextType]::Machine
$context = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList $ctype, "pcrs2"

## create the user object
$usr = New-Object -TypeName System.DirectoryServices.AccountManagement.UserPrincipal -ArgumentList $context

## set the properties
$usr.SamAccountName = "Newuser1"
$usr.SetPassword($cred.GetNetworkCredential().Password)
$usr.DisplayName = "New User"
$usr.Enabled = $true
$usr.ExpirePasswordNow()

## save the user
$usr.Save()

 

Add-Type is PowerShell v2 and you will need .NET 3 to use the Accountmanagement classes.  Given where we are in the Windows 7 lifecycle (a feeding frenzy in the press over when the RC will ship) I will be concentrating on PS 2

The script reads a password (we’ll replace that with a call to new-password) and uses the Accountmanagement classes to create the user account

The line

Add-Type -AssemblyName System.DirectoryServices.AccountManagement

becomes

# Assemblies that must be loaded prior to importing this module
RequiredAssemblies = @("System.DirectoryServices.AccountManagement")

in the module manifest.  This is good as I load it once and it will be available for all of my functions.

## create a password
$password = Read-Host "Password" –AsSecureString

becomes

$password = ConvertTo-SecureString -String $(new-password 8) -AsPlainText -Force

for a standard password. I’ll put switch parameters in later for a stronger password

so as a first pass the function looks like this

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
function new-user {
    [CmdletBinding()]
    param (
        [Parameter(Position=0,HelpMessage="The loginid")]
        [string]$id , 
       
        [Parameter(Position=1,HelpMessage="The Display name")]
        [string]$name 
       
    )   
    ## create a password
    $password = ConvertTo-SecureString -String $(new-password 8) -AsPlainText -Force
    $cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "userid", $password

    ## get the machine
    $pc = $env:computername
    ## create the context i.e. connect to the domain
    $ctype = [System.DirectoryServices.AccountManagement.ContextType]::Machine
    $context = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList $ctype, $pc

    ## create the user object
    $usr = New-Object -TypeName System.DirectoryServices.AccountManagement.UserPrincipal -ArgumentList $context

    ## set the properties
    $usr.SamAccountName = $id
    $usr.SetPassword($cred.GetNetworkCredential().Password)
    $usr.DisplayName = $name
    $usr.Enabled = $true
    $usr.ExpirePasswordNow()

    ## save the user
    $usr.Save()   
}

 

We can look at groups next.

Forest and domain modes

We can find the forest and domain modes using the following commands

Get-ADDomain -Identity grayson | select DomainMode

Get-ADForest grayson | select forestmode

The modes can be set from the GUI as normal or

Set-ADDomainMode -Identity grayson -DomainMode Windows2008R2Domain
Set-ADForestMode -Identity grayson -ForestMode Windows2008R2Forest

Not that you will be using these cmdlets very often

 

Two PowerShells

Windows Server 2008 R2 is 64 bit only so we we get two instances of PowerShell and ISE.  One (64bit version) is just labelled Windows PowerShell V2 and Windows PowerShell V2 ISE.  The 32bit version has (x86) appended to the name.

One point to watch for – the 64 and 32bit versions have different execution policies – you need to set both

Technorati Tags: ,,