Categories

Monthly Archives: June 2014

Workflows: 2 Additional reading

If you’re really interested in using workflows you may find this series of articles I did for the Scripting Guy useful:

1. Basics - introduce workflows, key concepts and keywords
http://blogs.technet.com/b/heyscriptingguy/archive/2012/12/26/powershell-workflows-the-basics.aspx

2. Restrictions - cmdlets not available as workflow activities, using inlinescript, using variables
http://blogs.technet.com/b/heyscriptingguy/archive/2013/01/02/powershell-workflows-restrictions.aspx

3. Nesting work flows and functions
http://blogs.technet.com/b/heyscriptingguy/archive/2013/01/09/powershell-workflows-nesting.aspx

4. Workflows and the PowerShell job engine - suspending and resuming; checkpointing and recovery
http://blogs.technet.com/b/heyscriptingguy/archive/2013/01/16/powershell-workflows-job-engine.aspx

5. Workflows and computer restarts
http://blogs.technet.com/b/heyscriptingguy/archive/2013/01/23/powershell-workflows-restarting-the-computer.aspx

6. Workflow parameters - where's the best place to put the computername?
http://blogs.technet.com/b/heyscriptingguy/archive/2013/01/30/powershell-workflows-using-parameters.aspx

7. Considerations for designing workfows; when to use workflows vs jobs
http://blogs.technet.com/b/heyscriptingguy/archive/2013/02/06/powershell-workflows-design-considerations.aspx

8. A practical example
http://blogs.technet.com/b/heyscriptingguy/archive/2013/02/13/powershell-workflows-a-practical-example.aspx

Workflows: 1 Introduction

In a recent post I asked for areas of PowerShell that caused problems. Workflows were one of the things mentioned so I’ll start with a series of posts on that topic.

 

Workflows were introduced to PowerShell in version 3.0 of the Windows Management Framework with Windows 8/2012. A few changes have been made in version 4.0 of WMF (Windows 8.1/2012 R2).

On the surface workflow brings a number of interesting, and potentially very useful, aspects to PowerShell including:

- parallel execution

- ability to survive a reboot of remote or local machine

- ability to checkpoint the workflow and restart at that point

- your task is long running

- your task needs to be run asynchronously

- your task needs to be run on multiple devices

In reality these aims can be met without using workflows. You can use background jobs, multiple instances of a PowerShell script, remoting, scheduled jobs etc to run your tasks. One thing that workflows are good at though is surviving reboots.

 

Since the flurry of activity that marked their introduction there hasn’t been a lot of noise about workflows. I think that one of the reasons is that they are perceived to be too hard. Workflows look like PowerShell but are subtly different  - they aren’t actually PowerShell even though they use the same syntax. We’ll delve into what they are under the covers in a future post. For now they look like PowerShell and do stuff for us.

 

Here’s the world’s simplest workflow:

workflow ourfirstworkflow {
  "PowerShell rocks"
}

ourfirstworkflow

 

if you’re looking at that and thinking it looks like a PowerShell function you’d be right. Swap the workflow key word out for function and you get

function ourfirstworkflow {
  "PowerShell rocks"
}

ourfirstworkflow

 

Try running the workflow and the function. The function returns the string almost instantaneously. The workflow needs to build the workflow functions in the background before it can run. Any subsequent runs use the “compiled” (its not a true compile but the term serves for what’s happening) workflow and run just about as quick as the function.

 

One way to achieve parallelism in a work flow is to use the –parallel option on a foreach loop. This is especially useful for accessing a set of remote computers. For now though we’ll keep it simple

workflow alittlebitofparrallel {
param (
  [int[]]$numbers
)

foreach -parallel ($number in $numbers)
{
   "I am number $number"
}


}

alittlebitofparrallel -numbers (1..10)

 

The statement[s] within the foreach loop are run sequentially but the loop is run in parallel for all numbers. Just inputting 1..10 give these results on my machine:

I am number 10
I am number 9
I am number 8
I am number 7
I am number 6
I am number 5
I am number 4
I am number 3
I am number 2
I am number 1

 

However if you call the workflow with 100 numbers:

alittlebitofparrallel -numbers (1..100)

 

You will see some evidence of parallelism at work towards the bottom of the results. My test showed this as part of the output

I am number 45
I am number 43
I am number 11
I am number 8
I am number 14
I am number 51
I am number 49
I am number 52
I am number 48
I am number 46
I am number 10
I am number 7
I am number 47

 

This shows a very important result – the way parallel processing returns results is random-ish. If you need your results back in a predictable manner – parallel execution in a workflow is not what you want to be doing.

 

I’ll leave it there for now and next time we’ll look at another way to use parallelism and a way to force sequential activities when that is what you really need.

if you want some more workflow related reading try the help files

about_ActivityCommonParameters
about_Checkpoint-Workflow
about_Foreach-Parallel
about_InlineScript
about_Parallel
about_Sequence
about_Suspend-Workflow
about_WorkflowCommonParameters
about_Workflows

PowerShell Summit Europe 2014 Agenda

The agenda for the PowerShell Summit Europe 2014 is available on line.  See the link from http://powershell.org/wp/community-events/summit/

The Summit is a benefit of AWPP membership which will be available from 15 July 2014. We only have room for 60 attendees so please sign up early to avoid disappointment.

Difficult bits of PowerShell?

PowerShell has grown from the original 137 cmdlets to a huge many faceted management platform. Each new iteration of PowerShell sees new features – Remoting, Workflow, DSC, OneGet. I don’t expect that to change in the near future.

The sheer size of PowerShell means its very difficult to be an expert in everything?

Is there anything that you find particularly hard or need more examples?

Please leave a comment if there is something in particular you would like covered.

PowerShell Summit DSC sessions

Steve Murawski gave three exceptional sessions on using DSC at the recent PowerShell summit.

The videos of those sessions can be found here -

http://powershell.org/wp/2014/05/23/patterns-for-implementing-a-dsc-pull-server-environment/

http://powershell.org/wp/2014/05/22/building-scalable-configurations-with-dsc/

http://powershell.org/wp/2014/05/21/life-and-times-of-a-dsc-resource/

Highly recommended

PowerShell Summit Europe 2014 – – update 1

The PowerShell Summit in Europe for 2014 will be held in Amsterdam – 20 September to 1 October

Details are available here - http://eventmgr.azurewebsites.net/home/event/PSEU14

 

The agenda is shaping up nicely and we’re looking to publish that soon. Shortly after that we will be opening up the registration process. There are a limited number of places available so please keep an eye open for announcements from powershell.org

Rename a user account to the display name

I had a question left on my blog about renaming all of the user accounts in an OU had their name changed to match the display name.  I started by creating a few dummy accounts:

PS s> Get-ADUser -Filter * -SearchBase "OU=Test,DC=Sphinx,DC=org"  -Properties DisplayName | Format-Table DisplayName, Name -AutoSize

DisplayName Name
----------- ----
Green Fred  Fred Green
Green Jo    Jo Green
Green Dave  Dave Green

 

In the case of the first account the goal is to change the Name to match the display name.

One thing to be aware of with AD names – NEVER, NEVER, NEVER and I mean NEVER use a comma between the first and last parts of the name.

So

CN=Fred Green,OU=Test,DC=sphinx,DC=org

is good

CN=Green Fred,OU=Test,DC=sphinx,DC=org

is good

CN=Green, Fred,OU=Test,DC=sphinx,DC=org

is BAD, BAD, BAD.

The reason is that the comma is a delimiter between the parts of the distinguished name. LDAP doesn’t expect a comma between parts of an element so it errors.  You have to escape the comma so its treated as a literal character. I can guarantee that you will forget. Been there, done that & designed the T-Shirt.

 

Don’t use commas – its fair simpler and you’ll have less errors.

 

The only option to rename an object is to use Rename-ADObject

PS > Get-ADUser -Filter * -SearchBase "OU=Test,DC=Sphinx,DC=org"  -Properties DisplayName | foreach {Rename-ADObject -Identity $_.DistinguishedName -NewName $_.Displayname -PassThru}

 

You’ll get a display showing the new names.

If you want to check run the original test

PS > Get-ADUser -Filter * -SearchBase "OU=Test,DC=Sphinx,DC=org"  -Properties DisplayName | Format-Table DisplayName, Name -AutoSize

DisplayName Name
----------- ----
Green Fred  Green Fred
Green Jo    Green Jo
Green Dave  Green Dave

 

Job done

File system ACLS – inheritance

When you look at a FileSystemAccessRule it’llbe something like this:

FileSystemRights  : Modify, Synchronize
AccessControlType : Allow
IdentityReference : NT AUTHORITY\Authenticated Users
IsInherited       : True
InheritanceFlags  : None
PropagationFlags  : None

So far we haven’t dealt with the three inheritance flags.

Isinherited indicates that the permission is inherited from further up the file system tree

The Inheritance flags -  http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.inheritanceflags(v=vs.110).aspx – are from the System.Security.AccessControl.InheritanceFlags enumeration:

None

ContainerInherit – child containers (folders) inherit the permission

ObjectInherit – child leaf objects (files) inherit the permission

The popagation flags are from the System.Security.AccessControl.PropagationFlags enumeration - http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.propagationflags(v=vs.110).aspx

None – no inheritance flags are present

InheritOnly – ACE is propagated to child containers and leaf objects

NoPropagateInherit – specifies the ACE is NOT propagated to child objects

This leads to our function being modified to look like this:

function add-acl {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[ValidateScript({Test-Path -Path $_ })]
[string]$path,

[Parameter(Mandatory=$true)]
[string]$trusteeName,

[Parameter(Mandatory=$true)]
[ValidateSet("Read", "Write", "ListDirectory", "ReadandExecute", "Modify", "FullControl")]
[string]$permission = "Read",

[Parameter(ParameterSetName='NOinherit')]
[switch]$NOinherit,

[Parameter(ParameterSetName='Container')]
[switch]$containerinherit,

[Parameter(ParameterSetName='Object')]
[switch]$objectinherit,

[switch]$deny

)

$fsr = [System.Security.AccessControl.FileSystemRights]::$permission


if ($containerinherit -OR $objectinherit) {
$propflag = [System.Security.AccessControl.PropagationFlags]::InheritOnly
}
else {
$propflag = [System.Security.AccessControl.PropagationFlags]::None
}

 

if ($containerinherit) {
$inhflag = [System.Security.AccessControl.InheritanceFlags]::ContainerInherit
}

if ($objectinherit) {
$inhflag = [System.Security.AccessControl.InheritanceFlags]::ObjectInherit
}

if ($NOinherit) {
$inhflag = [System.Security.AccessControl.InheritanceFlags]::None
}

if ($deny) {
  $alwdny = [System.Security.AccessControl.AccessControlType]::Deny
}
else {
  $alwdny = [System.Security.AccessControl.AccessControlType]::Allow
}


$acr = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $trusteeName, $fsr, $inhflag, $propflag, $alwdny

$acl = Get-Acl -Path $path
$acl.AddAccessRule($acr)


Set-Acl -Path $path -AclObject $acl -Passthru
}

Examples of use:

add-acl -path C:\Test -trusteeName "$($env:COMPUTERNAME)\NewUser" -permission FullControl -NOinherit
add-acl -path C:\Test -trusteeName "$($env:COMPUTERNAME)\NewUser" -permission FullControl -containerinherit
add-acl -path C:\Test -trusteeName "$($env:COMPUTERNAME)\NewUser" -permission FullControl -objectinherit

Set the permissions on the folder, the subfolders and the files respectively.

If you want all three – run it three times as above

Function parameter validation – other validation options

Some other options you can use for validating your input include:

[ValidateCount(1,10)]

tests the number of values being passed to the parameter – must be within the range (including end points ) specified

 

[ValidateLength(1,10)]

tests the number of characters in a parameter value – must be within the specified range


[ValidatePattern("\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b")] ## IP Address
[ValidatePattern("[A-Z]{2,8}[0-9][0-9]")]

tests the input value against a regular expression – the value must match the pattern otherwise an error will be thrown

 

[ValidateRange(0,10)]

the value must be between the endpoints of the range specified

 

[ValidateSet("Low", "Average", "High")]
the value must be a member of the set of values specified

 

Using these, together with the ValidateScript and Validate  NotNullorEmpty options, provide you an easy way to test and validate your function inputs.  Much easier than writing your own code

DSC Resource Kit wave 4 now available

The next wave of the DSC resource kit has been released. Notable additions include support for configuring DNS and DHCP servers and your event logs.

Details from http://blogs.msdn.com/b/powershell/rss.aspx