April 2013 - Posts

Getting the folder name

Consider the file information from get-childitem

PS> $file = ls servicesv0.6.txt

 

Fullname gives the full path to the file

PS> $file.Fullname
C:\MyData\SkyDrive\Data\scripts\servicesv0.6.txt

 

if you use DirectoryName you get the full path to the parent directory

 

PS> $file.DirectoryName
C:\MyData\SkyDrive\Data\scripts

 

The easiest way to get the folder holding the path is like this

PS> Split-Path -Path $file.DirectoryName -Leaf
scripts

 

However on a Windows 8/PS 3 setup you can also do this

PS> $file.Directory | select -ExpandProperty Name
scripts

Posted by RichardSiddaway | with no comments

Don’t go mad on a one liner

Looking at my first group of entries for Beginners Event 1 I’ve noticed what seems like a fanatical attempt to squash everything onto one line.

command; command; command; command 

is NOT a one liner.  The ; marks the end of a line

command | command | command | command

IS a one liner, even if it goes onto multiple lines!

Don’t think one liner – think one PIPELINE

Posted by RichardSiddaway | with no comments

Read the Question

When my children were at school and going off for a test or exam the last thing I told them was read the question.

It seems this needs to be repeated for the Scripting Games.  The Beginners Event 1 involved MOVING files from one server to another. I have seen a significant number of answers that are COPYING files.

Close doesn’t count in the Scripting Games.

Please read the question before diving into an answer

Posted by RichardSiddaway | with no comments

WMI vs CIM speed tests–the final round

As a final test I want to see what happened when I ran multiple commands against the remote machine.

PS> 1..100 |
foreach {
Measure-Command -Expression{1..100 | foreach {
Get-WmiObject -Class Win32_ComputerSystem -ComputerName W12SUS;
Get-WmiObject -Class Win32_OperatingSystem -ComputerName W12SUS;
Get-WmiObject -Class Win32_LogicalDisk -ComputerName W12SUS}}
} |
Measure-Object -Average TotalMilliseconds


Count    : 100
Average  : 6986.797156
Sum      :
Maximum  :
Minimum  :
Property : TotalMilliseconds


PS> 1..100 |
foreach {
Measure-Command -Expression{1..100 | foreach {
Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName W12SUS;
Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName W12SUS;
Get-CimInstance -ClassName Win32_LogicalDisk -ComputerName W12SUS}}
} |
Measure-Object -Average TotalMilliseconds


Count    : 100
Average  : 8430.833188
Sum      :
Maximum  :
Minimum  :
Property : TotalMilliseconds

 

PS> $sess = New-CimSession -ComputerName W12SUS
PS> 1..100 |
foreach {
Measure-Command -Expression{1..100 | foreach {
Get-CimInstance -ClassName Win32_ComputerSystem -CimSession $sess;
Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $sess;
Get-CimInstance -ClassName Win32_LogicalDisk -CimSession $sess}}
} |
Measure-Object -Average TotalMilliseconds


Count    : 100
Average  : 3460.203938
Sum      :
Maximum  :
Minimum  :
Property : TotalMilliseconds

WMI is slightly faster than CIM but using a CIM session is by far and away the fastest.

My conclusion is that WMI and CIM are comparable, with WMI having a slight edge for speed. If you want to run multiple commands against a remote machine you need to use a CIM session as it is way faster.

Backticks are baaaaaad; don’t do backticks

The voting/judging process has started for event 1 in the 2013 Scripting Games.  What I’m going to be doing over the next few weeks is point out some of the things that I’ve noticed when judging. Some will be good things that I think you should adopt; others will be bad things that you should avoid. There even may be some interesting stuff to get you thinking.

First off is the use of the backtick as a line continuation:

Get-Process | `
sort Handles –Descending

You don’t need a backtick at this point.  The pipe symbol acts as a line continuation marker so the backtick is redundant. All you need to do is this:

Get-Process |
sort Handles -Descending

Its the same with commas. You don’t need to do this:

Get-Process |
select Name, Id, `
Handles, CPU

because it works without the backtick

Get-Process |
select Name, Id,
Handles, CPU

You may see backticks used a lot in books but that is an attempt to reduce the width of the code to make it fit the page. We want you to be able to copy the code from the ebook and run it. The alternative is a line continuation marker which you would have to remove.

Bottom line – 99.9% recurring of the time you don’t need backticks as line continuation markers

Posted by RichardSiddaway | with no comments

CIM vs WMI cmdlets-remote execution speed

Following on from my previous post we’ll look at how the two types of cmdlets compare for accessing remote machines.

I used a similar format to the previous tests but was accessing a remote machine.

First off was the WMI cmdlet – using DCOM to access the remote Windows 2012 server

PS> 1..100 |
foreach {
Measure-Command -Expression{1..100 | foreach {Get-WmiObject -Class Win32_ComputerSystem -ComputerName W12SUS }}
} |
Measure-Object -Average TotalMilliseconds


Count    : 100
Average  : 2084.122547
Sum      :
Maximum  :
Minimum  :
Property : TotalMilliseconds

 

The CIM cmdlets are similar but apparently a bit slower – probably due to having to build the WSMAN connection and teat it down each time.


PS> 1..100 |
foreach {
Measure-Command -Expression{1..100 | foreach {Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName W12SUS }}
} |
Measure-Object -Average TotalMilliseconds


Count    : 100
Average  : 2627.287458
Sum      :
Maximum  :
Minimum  :
Property : TotalMilliseconds

 

So what happens is you run the CIM command over a CIM session?


PS> $sess = New-CimSession -ComputerName W12SUS
PS> 1..100 |
foreach {
Measure-Command -Expression{1..100 | foreach {Get-CimInstance -ClassName Win32_ComputerSystem -CimSession $sess }}
} |
Measure-Object -Average TotalMilliseconds


Count    : 100
Average  : 877.746649999999
Sum      :
Maximum  :
Minimum  :
Property : TotalMilliseconds

This removes the setup and tear-down of the WSMAN connection. It suggests that the actual retrieval time for the CIM cmdlets should be reduced to 1749.540808 milliseconds for 100 accesses which is faster than the WMI cmdlets

It looks like the fastest way to access WMI information is across a CIM session. Next time we’ll look at running multiple commands

AD Management in a Month of Lunches– chapter 9 in MEAP

The MEAP for AD Management in a Month of Lunches has been updated with the release of chapter 9 on managing group policies

CIM cmdlets vs WMI cmdlets–speed of execution

One question that came up at the summit was the comparative speed of execution of the new CIM cmdlets vs the old WMI cmdlets.  No of us knew the answer because we’d never tried measuring the speed.

I decided to perform some tests.

This first test is accessing the local machine.  In both cases the cmdlets are using COM.  WMI uses COM and CIM will use COM if a –ComputerName parameter isn’t used.

The results are as follows:

PS> 1..100 |
foreach {Measure-Command -Expression {
1..100 | foreach {Get-WmiObject -Class Win32_ComputerSystem} }
} | Measure-Object -Average TotalMilliseconds


Count    : 100
Average  : 2008.953978
Sum      :
Maximum  :
Minimum  :
Property : TotalMilliseconds

 

PS> 1..100 |
foreach {Measure-Command -Expression {
1..100 | foreach {Get-CimInstance -ClassName Win32_ComputerSystem} }
} | Measure-Object -Average TotalMilliseconds


Count    : 100
Average  : 2078.763174
Sum      :
Maximum  :
Minimum  :
Property : TotalMilliseconds

 

So for pure COM access the WMI cmdlets are marginally (3.4%) faster.

What if we use the ComputerName parameter?

PS> 1..100 |
foreach {
Measure-Command -Expression {
1..100 | foreach {Get-WmiObject -Class Win32_ComputerSystem -ComputerName $env:COMPUTERNAME } }
} | Measure-Object -Average TotalMilliseconds


Count    : 100
Average  : 1499.14379
Sum      :
Maximum  :
Minimum  :
Property : TotalMilliseconds

PS> 1..100 |
foreach {
Measure-Command -Expression {
1..100 | foreach {Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName $env:COMPUTERNAME } }
} | Measure-Object -Average TotalMilliseconds


Count    : 100
Average  : 3892.921851
Sum      :
Maximum  :
Minimum  :
Property : TotalMilliseconds


This one surprised me – the WMI cmdlets are 2.5 times faster.  I suspect that is because the CIM cmdlet has to build and then breakdown the WSMAN connection each time.

Next time we’ll look at accessing a remote machine.

Posted by RichardSiddaway | with no comments
Filed under:

Time for D-CRUD?

I was thinking on the plane back from the PowerShell summit about the CRUD activities. They are a concept we have inherited from the database world:

C = Create

R = Read

U = Update

D= Delete

Create, Update and Delete correspond directly to the PowerShell verbs – New,Set and Remove respectively.

The Read action corresponds to the Get verb.

Well sort of.

Get-* is used in two distinct scenarios.  Firstly we know of an object and we we want to read its properties – for example:

Get-Process -Name powershell

We are reading the information about the PowerShell process. That corresponds directly to the Read action in the CRUD paradigm.

However, we also use Get* when we want to Discover the processes that are running:

Get-Process

In which case we are Discovering the processes that are running.

I think its time to update the CRUD concept and make it DCRUD where D stands for discovery.

Posted by RichardSiddaway | with no comments
Filed under: ,

Scripting Games 2013 have started

The 2013 Scripting Games kicked off during the PowerShell summit.  Event 1 is open and you can submit entries up until 23:59:59 GMT on 29 April 2013.  Voting on the entries starts at at midnight on 30 April.

You can enter and you can vote on the entries.  This is a community games run by powershell.org – all are welcome.

If you haven’t entered yet there is still plenty of time to get you entry in for event 1.  Start by reviewing the information at http://powershell.org/wp/the-scripting-games/

Enjoy and good luck

Posted by RichardSiddaway | with no comments

PowerShell Summit–thank you

I’d like to extend a huge thank you to everyone who attended the PowerShell Summit this last week.  The Summit was a success – in no small part due to you. Your questions, and discussions, are what this is all about.

It was a pleasure meeting you all and I hope to return next year – I hope to see many of you there as well.

Posted by RichardSiddaway | with no comments
Filed under: ,

PowerShell Deep Dives–another MEAP release

 

Manning have released another set of chapters in their early access program for PowerShell Deep Dives.

If you have an interest in PowerShell I would strongly urge you to buy a copy. It has chapters from a number of well known PowerShell authors together with some very good material from new authors.  Best of all the royalties are going to charity.

Posted by RichardSiddaway | with no comments
Filed under: ,

Busy, busy, busy

A very busy time coming up in PowerShell land with the first PowerShell Summit kicking off in just over a week’s time.  The 2013 Scripting Games will also be starting very soon.

I’ll try and post about both of them as time allows

Posted by RichardSiddaway | with no comments

Creating a new disk

I really like Windows Server Core. The concept has come of age in Windows 2012.

I needed to add a new disk to a virtual machine  - that’s easy using the Hyper-V cmdlets. But what about formating the disk.

A module new to Windows 2012 & Windows can be used.  Its the Storage module.  I’ve not had chance, or reason, to play with this module yet. So many cmdlets so little time.

Start with viewing the disks:

PS C:\Users\richard> Get-Disk | ft -a

Number Friendly Name          OperationalStatus Total Size Partition Style
------ -------------          ----------------- ---------- ---------------
0      Virtual HD ATA Device  Online                120 GB MBR
1      Microsoft Virtual Disk Offline               127 GB RAW

 

Disk 1 is the new disk so need to initialise it.

PS C:\Users\richard> Initialize-Disk -Number 1 -PartitionStyle MBR

View the disks again

PS C:\Users\richard> Get-Disk | ft -a

Number Friendly Name          OperationalStatus Total Size Partition Style
------ -------------          ----------------- ---------- ---------------
0      Virtual HD ATA Device  Online                120 GB MBR
1      Microsoft Virtual Disk Online                127 GB MBR

 

Create a partition on the disk -   -useMaximimSize means use all of the disk for this partition

PS C:\Users\richard> New-Partition -DiskNumber 1 -UseMaximumSize -DriveLetter R

Now view the partitions

PS C:\Users\richard> Get-Partition | ft -a


   Disk Number: 0

PartitionNumber DriveLetter Offset         Size Type
--------------- ----------- ------         ---- ----
1                           1048576      350 MB IFS
2               C           368050176 119.66 GB IFS


   Disk Number: 1

PartitionNumber DriveLetter Offset    Size Type
--------------- ----------- ------    ---- ----
1               R           1048576 127 GB Logical

And finally format the new disk:

PS C:\Users\richard> Get-Volume | where DriveLetter -eq R | Format-Volume -FileSystem NTFS -NewFileSystemLabel Backup

Confirm
Are you sure you want to perform this action?
Warning, all data on the volume will be lost!
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): Y

You get a nice friendly warning (you could bypass using –Confirm $false) and the format happens

You could pipe the cmdlets together to do everything in one pass. Best of all – the cmdlets are WMI based.

Windows Server Backup

Windows Server 2012 has a PowerShell enabled backup utility. When you enable the feature you get a module called WindowsServerBackup.  It has the cmldets you would expect for creating and managing backups. No surprise you may say as this was avialable in Windows 2008 R2.

The difference with Windows Server 2012 is that you can do restores from PowerShell cmdlets whcih wasn’t available in the earlier version.

The restore cmdlets are

Start-WBFileRecovery

Start-WBHyperVRecovery

Start-WBSystemStateRecovery

Start-WBVolumeRecovery

 

This might not replace your currebt backup system but is very useful for backing up test environments and experimenting with things like authorative AD restores.

Running workflows

I tripped over an interesting issue recently regarding the running of PowerShell workflows.

Consider the world’s simplest workflow

workflow test-w1 {"hello world"}

If I run this on a 32bit Windows 8  PowerShell machine – it works

If I run this on Windows 2012 (64bit) on PowerShell it works

if I run this on Windows 2012 PowerShell (x86) – it doesn’t work!

Be aware of how you are running your workflows

Posted by RichardSiddaway | with no comments
Filed under:

AD Management in a Month of Lunches

The MEAP marches on with chapter 8 now released:

Chapter 8 – creating Group Policies

details from http://www.manning.com/siddaway3/

Manning Deal of the Day – April 6 2013

My PowerShell and WMI book will be Manning’s deal of the day for 6 April 2013.  The deal will go live at Midnight US ET and will stay active for about 48 hours.

This is your chance to get the book with a 50% discount.

Use code dotd0406au at manning.com/siddaway2/

The Deal of the Day offer also applies to SharePoint Workflow in Action (http://www.manning.com/wicklund/).

Enjoy

Posted by RichardSiddaway | with no comments

Putting the date in a file name

I often need to create file names that include the date & time the file was created in the name. I’ve come up with all sorts of ways to do but this I think is the simplest.

I want the date in this format:  year-month-day-hour-minute-second.  In other words a format that is easily sortable. I discovered that if you convert a data to a string there is a formatter that does most of the work for you.  That’s a lower case s.

PS> (Get-Date).ToString("s")
2013-04-03T20:09:31

You can’t have a : symbol in a file name so need to get rid of those

PS> (Get-Date).ToString("s").Replace(":","-")
2013-04-03T20-10-02

To complete the file name

PS> $datestring = (Get-Date).ToString("s").Replace(":","-")
PS> $file = "c:\folder\Prefix_$datestring.txt"
PS> $file
c:\folder\Prefix_2013-04-03T20-16-48.txt
PS>

I’ve done this as a two step process otherwise when you replace the : you also take out the one for the disk drive – oops

Enjoy

Posted by RichardSiddaway | 3 comment(s)
Filed under:

PowerShell excerpt week

The Scripting Guy is running a series of excerpts from the PowerShell books published by Manning.  Today is PowerShell in Practice http://blogs.technet.com/b/heyscriptingguy/archive/2013/04/03/excel-spreadsheets.aspx

Check out the deals all this week on Manning PowerShell books

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