PowerShell for Windows Admins


June 11, 2014  2:18 PM

Rename a user account to the display name

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Active Directory Administration

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

June 10, 2014  12:44 PM

File system ACLS – inheritance

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
NTFS permissions

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


June 8, 2014  7:32 AM

Function parameter validation – other validation options

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

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

test 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


June 7, 2014  9:33 AM

DSC Resource Kit wave 4 now available

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

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


June 6, 2014  7:36 AM

PowerShell Summit NA 2014 sessions

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

The slides and code from my three sessions

WSMAN cmdlets

Networking administration

Cmdletize the Registry

are available from

http://powershell.org/wp/2014/05/22/na-2014-powershell-summit-wrap-up-and-speaker-slides/

You can find videos of some of the sessions – including my three here

http://powershell.org/wp/2014/05/16/powershell-summit-n-a-2014-session-videos/


June 4, 2014  1:18 PM

Function parameter validation–ValidateScript

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Sometimes you need a little bit more than the standard parameter validation options can provide – in that case use ValidateScript – you can write your own validation routine. For example:

function test {
[CmdletBinding()]
param (
[parameter(Mandatory=$true,ValueFromPipeLine=$true,ValueFromPipeLineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[ValidateScript({Test-Path -Path $_})]
[string]$Path
)

$path

}

All I’ve done to the function used last time is that I’ve added

[ValidateScript({Test-Path -Path $_})]

This will test the path you input to determine if it exists.

Supply a path

£> test -Path C:\Test
C:\Test

and the function works as expected.

£> test -Path
test : Missing an argument for parameter ‘Path’. Specify a parameter of type ‘System.String’ and try again.
At line:1 char:6
+ test -Path
+      ~~~~~
+ CategoryInfo          : InvalidArgument: (:) [test], ParameterBindingException
+ FullyQualifiedErrorId : MissingArgument,test
Miss off the value of –path and you get the error telling you that the argument is missing. Being able to have multiple validation tests does give you the most flexibility.

£> test -Path C:\Test22
test : Cannot validate argument on parameter ‘Path’. The “Test-Path -Path $_” validation script for the argument with
value “C:\Test22″ did not return a result of True. Determine why the validation script failed, and then try the command
again.
At line:1 char:12
+ test -Path C:\Test22
+            ~~~~~~~~~
+ CategoryInfo          : InvalidData: (:) [test], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,test
In this case an invalid path is supplied and the validation script runs and determines that the path is invalid.

In case you were wondering about the order of validation – in this case it doesn’t matter if you change the order

function test {
[CmdletBinding()]
param (
[parameter(Mandatory=$true,ValueFromPipeLine=$true,ValueFromPipeLineByPropertyName=$true)]
[ValidateScript({Test-Path -Path $_})]
[ValidateNotNullOrEmpty()]
[string]$Path
)

$path

}

£> test -Path C:\Test
C:\Test

£> test -Path
test : Missing an argument for parameter ‘Path’. Specify a parameter of type ‘System.String’ and try again.
At line:1 char:6
+ test -Path
+      ~~~~~
+ CategoryInfo          : InvalidArgument: (:) [test], ParameterBindingException
+ FullyQualifiedErrorId : MissingArgument,test
£> test -Path C:\Test22
test : Cannot validate argument on parameter ‘Path’. The “Test-Path -Path $_” validation script for the argument with
value “C:\Test22″ did not return a result of True. Determine why the validation script failed, and then try the command
again.
At line:1 char:12
+ test -Path C:\Test22
+            ~~~~~~~~~
+ CategoryInfo          : InvalidData: (:) [test], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,test
The validation tests fail as expected.


June 3, 2014  11:57 AM

Function parameter validation–NotNullorEmpty

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

A question on the forum made me realise that there is still  a lot of confusion around the advanced function parameter validation options so I thought I’d spend  a few posts clearing some of the confusion.

The question was about ValidateNotNullorEmpty so I’ll start with that one.

function test {
[CmdletBinding()]
param (
[parameter(Mandatory=$true,ValueFromPipeLine=$true,ValueFromPipeLineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[string]$Path
)

$path

}

If you supply a path – it’s echoed back to you:

£> test -Path C:\Test
C:\Test

If you don’t supply the path parameter you’ll be prompted for it:

£> test
cmdlet test at command pipeline position 1
Supply values for the following parameters:
Path: c:\test
c:\test

if you use the function and don’t supply a value:

£> test -Path
test : Missing an argument for parameter ‘Path’. Specify a parameter of type ‘System.String’ and try again.
At line:1 char:6
+ test -Path
+      ~~~~~
+ CategoryInfo          : InvalidArgument: (:) [test], ParameterBindingException
+ FullyQualifiedErrorId : MissingArgument,test

The validation routine kicks in.

The pipeline works as well:

£> Get-ChildItem -Path c:\ -Filter test | test
Test

Though notice that its returning Test instead of c:\test – that’s because Get-ChildItem doesn’t return a property called path but Name is the first string property accessible in the object which is why its used.

Now if you try to access a non-existent path in this way

£> Get-ChildItem -Path c:\ -Filter test27 | test
£>

You’ll get nothing returned  – because

Get-ChildItem -Path c:\ -Filter test27

doesn’t put anything on the pipeline so test is never called.

If you want to see the function work with a non-existent folder try this:

£> test -Path (Get-ChildItem -Path c:\ -Filter test27)
test : Cannot validate argument on parameter ‘Path’. The argument is null or empty. Provide an argument that is not null
or empty, and then try the command again.
At line:1 char:12
+ test -Path (Get-ChildItem -Path c:\ -Filter test27)
+            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidData: (:) [test], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,test

ValidateNotNullEmpty is a good test for determining if a value is present and not Null or an empty string. It should be paired where possible with mandatory=$true to ensure that the parameter is used.

This and other validation options are discussed in about_Functions_Advanced_Parameters


June 2, 2014  10:53 AM

Unavailable modules

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Windows 2012

Another question on the powershell.org forum centred on modules not available on down level versions of Windows – in this case the SmbShare module.

A large number of modules were introduced with Windows server 2012 (many are also available on Windows 8). Over 60% of this new functionality is created using CDXML. A WMI class is created to do the work. Calls to the class are wrapped in XML and the subsequent file can be published as a PowerShell module.

These are easy to spot as they have a .CDXML extension.

If you are having problems with a module that doesn’t appear to be on Windows Server 2008 R2 or earlier – check the file extension in the module folder on a Windows Server 2012 (R2) system– if its CDXML the WMI class almost certainly won’t be available on the earlier versions of Windows.


May 28, 2014  1:39 PM

File system ACLs–function to add ACL

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
NTFS permissions

I thought that today I’d start putting together a function to add an ACL to a file system object. The starting point is the code that stepped through the process in an earlier post:

http://msmvps.com/blogs/richardsiddaway/archive/2014/05/26/file-system-acls-creating-an-acl.aspx

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

[switch]$deny

)

$fsr = [System.Security.AccessControl.FileSystemRights]::$permission
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, $alwdny

$acl = Get-Acl -Path $path
$acl.AddAccessRule($acr)
Set-Acl -Path $path -AclObject $acl -Passthru
}

The parameters supply the path to the object, the trustee receiving the permissions, the permission and if its being denied.

The function creates the appropriate objects for the file system rights and access control type and then creates an access rule.

Get-Acl is used to fetch the current acl to which the new access rule is added. Set-Acl is used to overwrite the ACL.

One thing that hasn’t been covered is the Inheritance flags – they will be added in the next iteration of the function.


May 28, 2014  12:51 PM

PowerShell Scripting Best Practices

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

Ed Wilson is running a series on Best Practices on his Hey, Scripting Guy blog at the moment.  I especially like today’s which is on simple scripts.  I do a lot of quick and dirty scripts that end up being thrown away at the  end of the project or incorporated into more formal modules for reuse.

Simple scripts are a very powerful admin tool and one that a lot of people don’t think about as they are conditioned into the idea that everything should be a module and other big code concepts. Don’t get me wrong – modules and everything else around enterprise level scripting are very important and a lot of my work is done that way but the quick, utility style script still has its place.

Check out Ed’s article at

http://blogs.technet.com/b/heyscriptingguy/archive/2014/05/28/powershell-best-practices-simple-scripting.aspx


Forgot Password

No problem! Submit your e-mail address below. We'll send you an e-mail containing your password.

Your password has been sent to: