PowerShell for Windows Admins


July 17, 2015  12:37 PM

get-computerDN–dealing with non-existant computers

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Active Directory, Powershell

If you look at the working part of the code to discover the distinguished name of a computer:

 

£> $computer = ‘w12r2sus’
£> $filter = “(&(objectCategory=computer)(objectClass=computer)(cn=$computer))”
£> ([adsisearcher]$filter).FindOne().Properties.distinguishedname
CN=W12R2SUS,OU=Servers,DC=Manticore,DC=org

 

What happens if the computername you chose doesn’t exist?

 

£> $computer = ‘w12r2nope’
£> $filter = “(&(objectCategory=computer)(objectClass=computer)(cn=$computer))”
£> ([adsisearcher]$filter).FindOne().Properties.distinguishedname
£>

 

You don’t get anything returned

 

The filter is formed correctly

£> $filter
(&(objectCategory=computer)(objectClass=computer)(cn=w12r2nope))

 

The FindOne() method doesn’t return anything

 

£> ([adsisearcher]$filter).FindOne()
£>

 

If you’re just working with a single computer then not getting a result is a fair indication of a problem but if you’ve passed a number of  computer names to the function you need to know easily which ones aren’t present – especially if you save the results in a collection and want to do something else with them.

 

In this case I’d use write-warning to output a message that the machine wasn’t found:

 

£> $computer = ‘w12r2nope’
£> $filter = “(&(objectCategory=computer)(objectClass=computer)(cn=$computer))”
£> $result = ([adsisearcher]$filter).FindOne()
£>
£> if ($result) {
>> $result.Properties.distinguishedname
>> }
>> else {
>>  Write-Warning -Message “Computer not found: $computer”
>> }
>>
WARNING: Computer not found: w12r2nope
£>

 

Putting that code into yesterday’s function gives us:

 

function get-computerDN {
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact=”Low”)]

param (
[parameter(Position=0,
Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
HelpMessage=”Supply computer name” )]
[Alias(“CN”, “Computer”)]
[ValidateNotNullOrEmpty()]
[string[]]$computername
)
BEGIN{}#begin
PROCESS{

foreach ($computer in $computername) {
if ($psCmdlet.ShouldProcess(“$computer”, “Retreiving distinguished name”)) {
$filter = “(&(objectCategory=computer)(objectClass=computer)(cn=$computer))”
$result = ([adsisearcher]$filter).FindOne()

if ($result) {
$result.Properties.distinguishedname
}
else {
Write-Warning -Message “Computer not found: $computer”
}

} # end if ($psCmdlet.ShouldProcess(“$computer”, “Retreiving distinguished name”))
} # end foreach ($computer in $computername) {

}#process
END{}#end

<#
.SYNOPSIS
Returns distinguished name of a computer

.DESCRIPTION
Returns distinguished name of one or more computers in the domain.
Assumes connectivity to domain controller. Domain independent.

.PARAMETER  computername
Name of computer for which distinguished name will be returned

.EXAMPLE
get-computerDN -computername server02

Returns the distinguished name for server02.

Results are of the form:
CN=SERVER02,OU=Domain Controllers,DC=Manticore,DC=org

.NOTES
[adsisearcher] is a shortcut for System.DirectoryServices.DirectorySearcher
.LINK

#>

}

 

Which is used like this

£> ‘server02’, ‘w12r2sus’, ‘w12r2nope’ | get-computerDN
CN=SERVER02,OU=Domain Controllers,DC=Manticore,DC=org
CN=W12R2SUS,OU=Servers,DC=Manticore,DC=org
WARNING: Computer not found: w12r2nope

 

One thing you need to keep in mind when estimating the time you’ll take to write a script – you’ll be writing at least half as much again validation, error handling and help/comments compared to the actual working code

July 16, 2015  12:47 PM

get-computerDN function

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Active Directory, Powershell

Last time I showed a bare bones function for using [adsisearcher] to retrieve the distinguished name of a domain computer.

This is a somewhat expanded version of that function which adds in the sorts of features you’d want for a production ready function.

function get-computerDN {
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact=”Low”)]

param (
[parameter(Position=0,
Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
HelpMessage=”Supply computer name” )]
[Alias(“CN”, “Computer”)]
[ValidateNotNullOrEmpty()]
[string[]]$computername
)
BEGIN{}#begin
PROCESS{

foreach ($computer in $computername) {
if ($psCmdlet.ShouldProcess(“$computer”, “Retreiving distinguished name”)) {
$filter = “(&(objectCategory=computer)(objectClass=computer)(cn=$computer))”
([adsisearcher]$filter).FindOne().Properties.distinguishedname
}
}

}#process
END{}#end

<#
.SYNOPSIS
Returns distinguished name of a computer

.DESCRIPTION
Returns distinguished name of one or more computers in the domain.
Assumes connectivity to domain controller. Domain independent.

.PARAMETER  computername
Name of computer for which distinguished name will be returned

.EXAMPLE
get-computerDN -computername server02

Returns the distinguished name for server02.

Results are of the form:
CN=SERVER02,OU=Domain Controllers,DC=Manticore,DC=org

.NOTES
[adsisearcher] is a shortcut for System.DirectoryServices.DirectorySearcher
.LINK

#>

}

 

[CmdletBinding()] adds –whatif and other standard parameters. It should be always part of a production script.

The param block is expanded to make the parameter mandatory, work with the pipeline and supply a help message if the value isn’t given

A couple of aliases for the parameter are defined and the parameter can’t be Null or empty

The parameter also accepts an array of values rather than a single value.

The PROCESS block is used for the actual working code. A foreach loop is used to iterate through the computernames and the retrieval of the distinguished name is wrapped in a if statement to allow for –whatif scenarios

Finally some help is defined.  I always add help tot he end of function so that its out of the way when I’m working on the code. It spersonal preference. If you want to put your help somewhere else – feel free.

Using the function gives you more options:

Simple single computer:£> get-computerDN -computername server02
CN=SERVER02,OU=Domain Controllers,DC=Manticore,DC=org

Whatif:

£> get-computerDN -computername server02 -WhatIf
What if: Performing the operation “Retreiving distinguished name” on target “ser
ver02”.

multiple machines

£> get-computerDN -computername server02, w12r2sus
CN=SERVER02,OU=Domain Controllers,DC=Manticore,DC=org
CN=W12R2SUS,OU=Servers,DC=Manticore,DC=org

computername as positional parameter

£> get-computerDN server02, w12r2sus
CN=SERVER02,OU=Domain Controllers,DC=Manticore,DC=org
CN=W12R2SUS,OU=Servers,DC=Manticore,DC=org

parameter aliases

£> get-computerDN -computer server02, w12r2sus
CN=SERVER02,OU=Domain Controllers,DC=Manticore,DC=org
CN=W12R2SUS,OU=Servers,DC=Manticore,DC=org

£> get-computerDN -cn server02, w12r2sus
CN=SERVER02,OU=Domain Controllers,DC=Manticore,DC=org
CN=W12R2SUS,OU=Servers,DC=Manticore,DC=org

Help

£> Get-Help get-computerDN

NAME
get-computerDN

SYNOPSIS
Returns distinguished name of a computer

SYNTAX
get-computerDN [-computername] <String[]> [-WhatIf] [-Confirm]
[<CommonParameters>]

DESCRIPTION
Returns distinguished name of one or more computers in the domain.
Assumes connectivity to domain controller. Domain independent.
RELATED LINKS
REMARKS
To see the examples, type: “get-help get-computerDN -examples”.
For more information, type: “get-help get-computerDN -detailed”.
For technical information, type: “get-help get-computerDN -full”.
For online help, type: “get-help get-computerDN -online”

 

Full help
£> Get-Help get-computerDN -Full

NAME
get-computerDN

SYNOPSIS
Returns distinguished name of a computer

SYNTAX
get-computerDN [-computername] <String[]> [-WhatIf] [-Confirm]
[<CommonParameters>]

DESCRIPTION
Returns distinguished name of one or more computers in the domain.
Assumes connectivity to domain controller. Domain independent.
PARAMETERS
-computername <String[]>
Name of computer for which distinguished name will be returned

Required?                    true
Position?                    1
Default value
Accept pipeline input?       true (ByValue, ByPropertyName)
Accept wildcard characters?  false

-WhatIf [<SwitchParameter>]

Required?                    false
Position?                    named
Default value
Accept pipeline input?       false
Accept wildcard characters?  false

-Confirm [<SwitchParameter>]

Required?                    false
Position?                    named
Default value
Accept pipeline input?       false
Accept wildcard characters?  false

<CommonParameters>
This cmdlet supports the common parameters: Verbose, Debug,
ErrorAction, ErrorVariable, WarningAction, WarningVariable,
OutBuffer, PipelineVariable, and OutVariable. For more information,
see
about_CommonParameters
(http://go.microsoft.com/fwlink/?LinkID=113216).

INPUTS

OUTPUTS

NOTES

[adsisearcher] is a shortcut for
System.DirectoryServices.DirectorySearcher

————————– EXAMPLE 1 ————————–

PS C:\>get-computerDN -computername server02

Returns the distinguished name for server02.

Results are of the form:
CN=SERVER02,OU=Domain Controllers,DC=Manticore,DC=org

RELATED LINKS
mandatory parameter
£> get-computerDN
cmdlet get-computerDN at command pipeline position 1
Supply values for the following parameters:
(Type !? for Help.)
computername[0]:
get-computerDN : Cannot validate argument on parameter ‘computername’. The
argument is null, empty, or an element of the argument collection contains a
null value. Supply a collection that does not contain any null values and then
try the command again.
At line:1 char:1
+ get-computerDN
+ ~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidData: (:) [get-computerDN], ParameterBind
ingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,get-computerDN
Help message on mandatory parameter

£> get-computerDN
cmdlet get-computerDN at command pipeline position 1
Supply values for the following parameters:
(Type !? for Help.)
computername[0]: !?
Supply computer name
computername[0]:

Pipeline input

£> ‘server02’, ‘w12r2sus’ | get-computerDN
CN=SERVER02,OU=Domain Controllers,DC=Manticore,DC=org
CN=W12R2SUS,OU=Servers,DC=Manticore,DC=org

One thing missing is error handling – I’ll cover that next time


July 15, 2015  1:54 PM

ADSIsearcher returns

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Active Directory, Powershell

I’ve been using the Microsoft AD cmdlets (and before that the Quest cmdlets) for so long that I’d sort of forgotten about [adsisearcher].

It was introduced in PowerShell 2.0 and is a shortcut for System.DirectoryServices.DirectorySearcher

A question in the forum about using this remotely made me realise that many people have probably never used it before – and to think that 5 years ago it was the way to go – how things change.

The question revolved around using this code

$filter = “(&(objectCategory=computer)(objectClass=computer)(cn=$env:COMPUTERNAME))”
([adsisearcher]$filter).FindOne().Properties.distinguishedname

for other machines.

An attempt was made to use Invoke-Command but that won’t work because you are attempting to delegate you credentials to make the call to AD – and that’s not allowed under the default configuration for remoting. You also can’t guarantee that remoting is enabled on older machines.

All you have to do is replace $env:COMPUTERNAME with the name of the computer for which you want to get the distinguished name.  Easiest way to do this is with a function

function get-computerDN {
param ($computername)
$filter = “(&(objectCategory=computer)(objectClass=computer)(cn=$computername))”
([adsisearcher]$filter).FindOne().Properties.distinguishedname

}

This is an absolute bare bones function just to show the way the parameter is used – you should validate the input and add some error handling as basic improvements.

£> get-computerDN -computername server02
CN=SERVER02,OU=Domain Controllers,DC=Manticore,DC=org

Next time I’ll show how to take the basic functionality and create something a bit more robust


July 14, 2015  12:05 PM

Disk identification

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell, WMI

A recent question on the forums regarded using the Win32_LogicalDisk class to retrieve disk size and free space data.  A filter based on the disk letter was being used. The main error with the code was that the filter was being expressed as

“DeviceId=’E'”

rather than

“DeviceId=’E:”

The colon is necessary as its part of the DeviceId data – if you are in doubt about the form of the data required by the filter then examine the full output of the class to see an example.

There were a couple of other basic issues.

Firstly always output objects.

Secondly use the size constants MB, GB etc rather than calculating refresh each time.

The final modified code looks like this

$computername = $env:COMPUTERNAME
$partition = ‘C:’
$description = ‘backup_server’

Get-WmiObject -Class Win32_LogicalDisk -Filter “DeviceId=’$partition'”     -ComputerName $computername |
select PSComputerName,
@{Name=’Partition’; Expression={$_.DeviceId}},
@{Name=’Description’; Expression={$description}},
@{Name=’Size(GB)’;Expression={[math]::Round(($_.Size / 1GB), 2)}},
@{Name=’FreeSpace(GB)’;Expression={[math]::Round(($_.FreeSpace / 1GB), 2)}}


July 11, 2015  4:36 AM

PowerShell and messaging

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Messaging, MSMQ, Powershell, Windows Server 2012 R2

This article – http://powershell.org/wp/2015/07/07/rabbitmq-and-powershell/ – reminded me that Windows server comes with a built-in messaging system – MSMQ.

There is a PowerShell module for MSMQ – https://technet.microsoft.com/en-us/library/hh405007(v=vs.85).aspx

Since reading the RabbitMQ article I think that Rabbit is more useful in a heterogeneous environment but MSMQ would work very nicely in a Windows only environment.

I’ve not looked at MSMQ for a long time and not seen much on using it through PowerShell so I think its time to remedy that – I’ll put together a short series on using MSMQ through PowerShell to complement the RabbitMQ information


July 8, 2015  7:32 AM

PowerShell Gallery taking registrations

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

The PowerShell team have just announced that the PowerShell gallery is now open for YOU to post your module. You need to register to be able to post code to the gallery.

http://blogs.msdn.com/b/powershell/archive/2015/07/07/powershell-gallery-registration-is-now-unrestricted.aspx

This is a significant step forward in making PowerShell code available to others – if you have a cool module please share


July 7, 2015  11:05 AM

DSC validation

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

The PowerShell team are asking for validation and feedback on the DSC features in WMF 5.0 – http://blogs.msdn.com/b/powershell/archive/2015/07/06/validate-features-of-powershell-dsc.aspx

First up is the PowerShell DSC RunAsCredential – http://blogs.msdn.com/b/powershell/archive/2015/07/06/validate-powershell-dsc-runascredential.aspx

Other features will be explained and your validation solicited over the course of this week


July 7, 2015  5:47 AM

Number of working days

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

Need to know the number of working days left until a specific date?

 

$we = [System.DayOfWeek]::Saturday, [System.DayOfWeek]::Sunday

$date = Get-Date -Year 2015 -Month 8 -Day 28
$now = (Get-Date).AddDays(-1)

$workdays = 0

while ($now -le $date){

$now = $now.AddDays(1)

if ($now.DayOfWeek -notin $we ) {
$workdays++
}

}
$workdays

 

Create a collection of days you don’t want counting – in my case Saturday & Sunday

Set the date you want to count to and current date – the –1 on current day is to set the variable for the loop

 

In the loop increment the date and test against you collection of excluded days. Increment your workday counter and loop

 

Now you can work out how many days until that holiday , course or whatever.  The end date is included in the count by the way


July 5, 2015  8:09 AM

Scripting Guy new series

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

Ed Wilson, the Scripting Guy, is starting a new series of posts on writing PowerShell scripts – he’ll also cover what to script, when to script and when to work interactively.

First post is here http://blogs.technet.com/b/heyscriptingguy/archive/2015/07/05/weekend-scripter-when-to-write-a-powershell-script.aspx

Strongly recommend this series to all PowerShell users


July 4, 2015  5:21 AM

Scripting Games July 2015 puzzle

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

Head over to http://powershell.org/wp/2015/07/04/2015-july-scripting-games-puzzle/ for our inaugural Scripting Games puzzle.

I’ll publish a solution at the end of the month


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: