WindowWindows PowerShells PowerShell - Compressed
WindowWindows PowerShells PowerShell - Compressed
Windows PowerShell
Best Practices
Windows PowerShell
Best Practices
Wilson
Windows
PowerShell
BEST PRACTICES
microsoft.com/mspress
ISBN 978-0-7356-6649-8
5 5 9 9 9
U.S.A. $59.99
Canada $68.99
[Recommended]
780735 666498
666498_Win_PowerShell_Best_Practices.indd 1
Celebrating 30 years!
Ed Wilson
4/11/14 10:30 AM
Windows PowerShell
Best Practices
Ed Wilson
666498_book.indb 1
12/20/13 10:50 AM
666498_book.indb 2
12/20/13 10:50 AM
This book is dedicated to Teresa. You make each day feel like it is
filled with infinite possibilities.
Ed Wilson
666498_book.indb 3
12/20/13 10:50 AM
666498_book.indb 4
12/20/13 10:50 AM
Contents at a glance
Foreword xix
Introduction xxi
Part I
Chapter 1
Chapter 2
Part II
Chapter 3
Chapter 4
73
Chapter 5
111
Chapter 6
151
Chapter 7
195
Part III
Chapter 8
233
Chapter 9
277
Chapter 10
Designing modules
311
Chapter 11
339
Chapter 12
Handling errors
397
Chapter 13
Testing scripts
433
Chapter 14
Documenting scripts
475
Part IV
Chapter 15
491
Chapter 16
Running scripts
507
Chapter 17
Versioning scripts
521
Chapter 18
Logging results
531
Chapter 19
Troubleshooting scripts
559
666498_book.indb 5
3
27
45
12/20/13 10:50 AM
Chapter 20
605
Chapter 21
615
Chapter 22
643
Chapter 23
659
Index 675
About the Author
666498_book.indb 6
705
12/20/13 10:50 AM
Contents
Foreword xix
Introduction xxi
Part I
11
Confirming commands
12
12
14
15
17
21
Additional resources. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
What do you think of this book? We want to hear from you!
Microsoft is interested in hearing your feedback so we can continually improve our
books and learning resources for you. To participate in a brief online survey, please visit:
www.microsoft.com/learning/booksurvey/
vii
666498_book.indb 7
12/20/13 10:50 AM
27
29
30
33
34
Part II
45
47
47
50
56
59
Managing users
60
Creating a user
63
64
66
68
Additional resources. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
73
viii
666498_book.indb 8
77
77
78
Contents
12/20/13 10:50 AM
79
Structured requirements. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Security requirements
83
84
96
100
102
Application requirements
106
Module requirements
108
111
112
Creating functions
116
120
Creating variables
126
Creating PSDrives
133
Enabling scripting
139
141
143
147
148
151
160
666498_book.indb 9
ix
12/20/13 10:50 AM
173
175
180
Version dependencies
182
182
189
195
196
203
Fan-out commands
205
208
214
Part III
233
248
253
666498_book.indb 10
Contents
12/20/13 10:50 AM
277
285
287
288
295
296
297
298
Document prerequisites
299
Document deficiencies
300
302
303
303
304
305
306
307
311
312
Loading modules
316
Contents
666498_book.indb 11
xi
12/20/13 10:50 AM
319
322
324
326
330
339
340
348
362
372
376
Output to file
382
383
Output to email
387
388
397
398
399
xii
666498_book.indb 12
401
402
404
406
Contents
12/20/13 10:50 AM
410
412
429
430
433
438
440
442
445
446
450
460
462
464
475
666498_book.indb 13
xiii
12/20/13 10:50 AM
Part IV
491
492
492
493
495
496
499
507
509
512
515
515
516
517
517
521
xiv
666498_book.indb 14
522
523
Track changes
523
Contents
12/20/13 10:50 AM
523
523
525
531
532
Text location
542
548
554
555
559
560
560
564
568
572
581
587
Responding to breakpoints
596
Listing breakpoints
597
599
Deleting breakpoints
601
666498_book.indb 15
xv
12/20/13 10:50 AM
605
606
608
610
611
612
613
615
615
626
643
644
A simple workflow
644
649
650
650
Parallel activities
651
652
Placing checkpoints
652
Adding checkpoints
653
666498_book.indb 16
Contents
12/20/13 10:50 AM
659
660
Configuration parameters
663
Setting dependencies
665
Configuration data
666
Index 675
www.microsoft.com/learning/booksurvey/
Contents
666498_book.indb 17
xvii
12/20/13 10:50 AM
666498_book.indb 18
12/20/13 10:50 AM
Foreword
n April 2003, Microsofts Jeffrey Snover gave me an early peek at PowerShell or, as it was
known in its beta days, Monad. I must admit that, while I fell in love with PoSH at first
sight, I was just too darned busy with other work to really get my hands dirty with it for another five years, and I soon realized that boy, had I missed a few memos. Objects in a pipeline? Is that anything like snakes on a plane? Hash tables? Can I get mine with a fried egg?
Yup, there was a lot to learn, and I nearly wore out Google looking up PoSH-y things.
Just about every one of those searches, however, seemed to lead me to the same place: the
Hey, Scripting Guy! Blog. I quickly noticed that the blog delivered new articles daily, and so
I was very surprised to see that the vast majority of those articles were penned by one guy:
Ed W
ilson. Since then, Ive gotten to know Ed personally, and trust me, hes even funnier and
more entertaining in person than he is in print, which brings me to this volume.
If youre a Windows admin, learning Windows PowerShell is an essential (as in you need
to do this if you want to remain a Windows admin) task. Its not always an easy one, though,
and you will often find yourself wishing for the answers in the back of the book so to speak.
Well, Eds written that book, and youre holding the latest edition. Work your way through
Windows PowerShell Best Practices, actually take the time to try out the examples, and soon
you, too, will be automating, scripting, and workflow-ing like mad. Happy PowerShelling!
Mark Minasi, author of the Mastering Windows Server books
P.S. In case you dont already know, objects in a pipeline are way cooler than snakes on a
plane. Really.
xix
666498_book.indb 19
12/20/13 10:50 AM
666498_book.indb 20
12/20/13 10:50 AM
Introduction
elcome to Windows PowerShell Best Practices, a book that was developed together with
the Microsoft Windows PowerShell product group to provide in-depth information
about Windows PowerShell and best practices based on real-life experiences with the product
in use in different environments. Numerous sidebars are also included that detail experiences
from skilled industry professionals such as Enterprise Admins and Windows PowerShell Most
Valuable Professionals (MVPs).
The book is largely based on Windows PowerShell 4.0 as it exists on Windows 8.1 and
on Windows Server 2012 R2. Because Windows PowerShell introduced Desired State
Configuration in Windows PowerShell 4.0, Chapter 23, Using the Windows PowerShell DSC,
must be run on a computer with Windows PowerShell 4.0 installed on it. Nearly all of the
material in the other chapters will work without modification on Windows PowerShell 3.0 (on
Windows 8 or on Windows Server 2012). A large part of the book also applies to Windows
PowerShell 2.0 running on any version of Windows that it installs upon.
The first part of this book consists of two chapters that focus on the basics of Windows
PowerShell capabilities. This portion of the book is a level setting and would be ideal for anyone just learning Windows PowerShell.
xxi
666498_book.indb 21
12/20/13 10:50 AM
The second part of the book discusses identifying scripting opportunities, the scripting environment, and avoiding scripting pitfalls. This part is also ideal for people learning Windows
PowerShell, but it is also a great section for admins experienced with the fundamentals of
Windows PowerShell but who need to write new scripts.
The third section of the book talks about how you actually design a scripthow you
plan for inputs and outputs to the script and how you document your scripts. This is a more
advanced section, and it is appropriate for advanced students and for people who write
scripts that others are expected to utilize.
The last section of the book talks about deploying scriptshow you run them; how you
handle versioning; and how you use remote, workflow, and DSC capabilities in your script.
This is appropriate for enterprise admins who are firmly entrenched in DevOps.
System requirements
This book is designed to be used with the following Exchange 2010 software:
1 GB of RAM
x64 architecture-based computer with Intel or AMD processor that supports 64 bit
The following list details the minimum system requirements needed to run the content in
the books companion website:
Windows XP with the latest service pack installed and the latest updates from Microsoft Update Service
CD-ROM drive
xxii Introduction
666498_book.indb 22
12/20/13 10:50 AM
Job Aids Additional documents on most of the chapters that help you to collect and
structure your work through the book.
Quick Reference Guides These guides provide an overview of all best practice
recommendations in the book as well as a collection of all Internet links referenced in
the book.
You can download these files from the companion website, which is located at
http://gallery.technet.microsoft.com/scriptcenter/PowerShell-40-Best-d9e16039.
Acknowledgements
A book of this scope does not happen without assistance. First I must thank my wife,
Teresa Wilson, aka the Scripting Wife. She not only coordinated the acquisition of sidebars,
but she also read the entire book at least three times. My technical reviewer, Microsoft PFE
Brian Wilhite, was great at catching things that would have made me look silly. He also made
numerous suggestions for improving not only the clarity of the writing, but in some cases the
accuracy of the code. Brian absolutely rocks. Luckily, the Windows PowerShell community is
very enthusiastic and as a result was receptive for my call for sidebars. The high quality of the
sidebars, and the diversity of content was fun to read, and in the end makes for a much better
book. If you run across one of the authors of the sidebars, make sure you tell them "hi." Lastly,
I want to thank Jeffrey Snover, Ken Hansen and the rest of the Windows PowerShell team.
They made an awesome product that just keeps getting better and better each year. Windows PowerShell for the win!
Introduction xxiii
666498_book.indb 23
12/20/13 10:50 AM
Errata
We have made every effort to ensure the accuracy of this book. If you do find an error, please
report it on our Microsoft Press site:
http://aka.ms/PowershellBestPractices/errata
You will find additional information and services for your book on its catalog page. If
youneed additional support, please e-mail Microsoft Press Book Support at mspinput@
microsoft.com.
Please note that product support for Microsoft software is not offered through the
addresses above.
Stay in touch
Let us keep the conversation going! We are on Twitter: http://twitter.com/MicrosoftPress.
xxiv Introduction
666498_book.indb 24
12/20/13 10:50 AM
666498_book.indb 44
12/20/13 10:50 AM
CHAPTER 3
Additional resources
ome of us have been using Active Directory since the release candidates in
1999. Others have gotten started with it recently. But we all have one thing
45
666498_book.indb 45
12/20/13 10:50 AM
interface with the directory.) Those legacy scripting techniques faithfully carried us
through many implementations and change controls.
But in the autumn of 2009, our tools made a giant leap forward. Windows Server
2008 R2 and the RSAT for Windows 7 introduced the Active Directory PowerShell
Module. Wow! What would take 20 lines of VBScript can now be done in a single
line of Windows PowerShell.
Here are some great examples of AD PowerShell one-liners:
Spreadsheet of stale accounts past 30 days:
Search-ADAccount -AccountInactive -TimeSpan 30 | Export-CSV .\Stale_
Accts.csv
Helpdesk prompt for a user password reset:
Set-ADAccountPassword (Read-Host 'Username') -Reset
Target list of global catalog domain controllers:
(Get-ADForest).GlobalCatalogs
In my field experience, I have written some large-scale scripts as well, such as the
following:
Active Directory SID history cleanup and file server ACL migrations
On the domain controller, this magic is made possible by the Active Directory
Web Service (ADWS). The ADWS listens on port 9389 and answers to the Windows
PowerShell cmdlets. Whether youre running a quick one-liner or automating across
thousands of accounts, this service enables you to read and write directory data
with ease.
With each release of Windows Server, the Active Directory module (and now companion modules) grows to support new features. The latest releases offer additional
functionality to replace trusty utilities like DCPROMO and REPADMIN. Additionally,
the Group Policy module enables further automation of workstation management
through Active Directory.
The Active Directory module for Windows PowerShell is no longer new technology. This is a mature product that every administrator needs in their bag of tricks
to make the work day go faster. Get started today with one simple Windows
PowerShell command: Import-Module ActiveDirectory.
46
CHAPTER 3
666498_book.indb 46
12/20/13 10:50 AM
The output associated with getting and installing the rsat-ad-tools feature is shown in
Figure 3-1.
FIGURE 3-1Installing the RSAT tools provides access to the Active Directory module.
666498_book.indb 47
CHAPTER 3
47
12/20/13 10:50 AM
After the ActiveDirectory module loads, you can obtain a listing of the Active Directory
cmdlets by using the Get-Command cmdlet and specifying the module parameter. Because
Windows PowerShell 4.0 automatically loads modules, you do not need to use the ImportModule cmdlet to import the ActiveDirectory module if you do not want to do so. This command is shown here:
Get-Command -Module ActiveDirectory
If you do not want to install the Active Directory module on your client operating systems,
all you need to do is to add the rsat-ad-tools feature to at least one server. When installed on
the server, use Windows PowerShell remoting to connect to the server hosting the rsat-adtools feature from your client workstation. When in the remote session, if the remote server is
Windows 8, all you need to do is call one of the Active Directory cmdlets. The ActiveDirectory
module automatically loads, and the information returns. The following commands illustrate
this technique:
$credential = get-credential
Enter-PSSession -ComputerName w8Server6 -Credential $credential
Get-ADDomain
The technique to use Windows PowerShell remoting to connect to a server that contains
the Active Directory module and to automatically load that module while using a cmdlet from
that module on Windows PowerShell 4.0 is shown in Figure 3-2.
48
CHAPTER 3
666498_book.indb 48
12/20/13 10:50 AM
FIGURE 3-2Using Windows PowerShell 4.0 remoting to obtain Active Directory information without first
ike most Windows administrators, you probably work with Active Directory
on a weekly, if not daily, basis. With Windows PowerShell, working with Active
Directory is so much easier than it used to be. In fact, Ive forgotten how complex
structuring ADSI code can be. When installing a fresh copy of Windows, usually after customizing my profile, I will download and install the Remote Server
Administration Tools (RSAT), to ensure that I have the ActiveDirectory Module for
use within Windows PowerShell. From time to time, my manager has asked me
to run a query against Active Directory to determine what computers have been
enabled for delegation, for compliance reasons, and to possibly execute a task on
those systems. So I turn to Windows PowerShell, with the ActiveDirectory module,
for the answer.
First, you need to determine what Active Directory attributes to filter for. In my
case, Im looking for any computer object that has a value present for the msDSAllowedToDelegateTo attribute or the TrustedForDelegation attribute value set to
true. The Active Directory module has a cmdlet that will allow me to query Active
Directory for these attributes and their settings. Consider the following example:
666498_book.indb 49
CHAPTER 3
49
12/20/13 10:50 AM
Get-ADComputer '
-Filter {msDS-AllowedToDelegateTo -like "*" -or TrustedForDelegation
-eq "True"} '
-Properties TrustedForDelegation, msDS-AllowedToDelegateTo |
Select Name, TrustedForDelegation, msDS-AllowedToDelegateTo
This will return any computer object that is trusted for delegation to any service
or specific services. Finally, lets assume that you want to take those computers
and query the Windows Updates that have been applied to them. You can run the
following one-liner, assuming Windows PowerShell remoting is enabled on the
targets, to pipe the results into the Invoke-Command cmdlet, launching Get-HotFix
on the target machine, and storing the results in a variable:
$Results = Get-ADComputer '
-Filter {msDS-AllowedToDelegateTo -like "*" -or TrustedForDelegation -eq
"True"} '
-Properties TrustedForDelegation, msDS-AllowedToDelegateTo |
Select Name, TrustedForDelegation, msDS-AllowedToDelegateTo |
ForEach-Object {Invoke-Command -Command {Get-HotFix} -ComputerName
$_.Name}
After this runs, which might take a few minutes, given the number of computers,
you will have a nice report that you can review. If you wanted to take it a step further, you could take the results variable and pipe it to a CSV file:
$Results | Export-Csv -Path C:\Temp\DelegationPatchReport.csv
Windows PowerShell with the ActiveDirectory module will make a Windows administrators life easy when given a task big or small.
50
CHAPTER 3
666498_book.indb 50
12/20/13 10:50 AM
ModuleType
---------Script
Script
Script
Script
Script
Script
Script
Script
Script
Script
Manifest
Manifest
Manifest
Manifest
Manifest
Manifest
Script
Manifest
Name
---BasicFunctions
ConversionModuleV6
PowerShellPack
PSCodeGen
PSImageTools
PSRss
PSSystemTools
PSUserTools
TaskScheduler
WPK
ActiveDirectory
AppLocker
BitsTransfer
FailoverClusters
GroupPolicy
NetworkLoadBalancingCl...
PSDiagnostics
TroubleshootingPack
ExportedCommands
---------------{Get-ComputerInfo, Get-OptimalSize}
{ConvertTo-Feet, ConvertTo-Miles, ConvertTo-...
{New-ByteAnimationUsingKeyFrames, New-TiffBi...
{New-Enum, New-ScriptCmdlet, New-PInvoke}
{Add-CropFilter, Add-RotateFlipFilter, Add-O...
{Read-Article, New-Feed, Remove-Article, Rem...
{Test-32Bit, Get-USB, Get-OSVersion, Get-Mul...
{Start-ProcessAsAdministrator, Get-CurrentUs...
{Remove-Task, Get-ScheduledTask, Stop-Task, ...
{Get-DependencyProperty, New-ModelVisual3D, ...
{Set-ADOrganizationalUnit, Get-ADDomainContr...
{Get-AppLockerPolicy, Get-AppLockerFileInfor...
{Start-BitsTransfer, Remove-BitsTransfer, Re...
{Set-ClusterParameter, Get-ClusterParameter,...
{Get-GPStarterGPO, Get-GPOReport, Set-GPInhe...
{Stop-NlbClusterNode, Remove-NlbClusterVip, ...
{Enable-PSTrace, Enable-WSManTrace, Start-Tr...
{Get-TroubleshootingPack, Invoke-Troubleshoo...
PS C:\>
After you have loaded the Active Directory module, you will want to use the Get-Command
cmdlet to see the cmdlets that are exported by the module. This is shown here:
PS C:\> Get-Module -ListAvailable
ModuleType
---------Script
Script
Script
Manifest
Manifest
Manifest
Manifest
Manifest
Manifest
Manifest
Manifest
Manifest
Manifest
Manifest
Manifest
Manifest
Manifest
Manifest
Manifest
Manifest
Manifest
Name
---BasicFunctions
ConversionModuleV6
DotNet
FileSystem
IsePack
PowerShellPack
PSCodeGen
PSImageTools
PSRSS
PSSystemTools
PSUserTools
TaskScheduler
WPK
ActiveDirectory
AppLocker
BitsTransfer
FailoverClusters
GroupPolicy
NetworkLoadBalancingCl...
PSDiagnostics
TroubleshootingPack
ExportedCommands
---------------{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
666498_book.indb 51
CHAPTER 3
51
12/20/13 10:50 AM
Definition
---------Add-ADComputerServiceAccount [...
Add-ADDomainControllerPassword...
Add-ADFineGrainedPasswordPolic...
Add-ADGroupMember [-Identity] ...
Add-ADPrincipalGroupMembership...
Clear-ADAccountExpiration [-Id...
Disable-ADAccount [-Identity] ...
Disable-ADOptionalFeature [-Id...
Enable-ADAccount [-Identity] <...
Enable-ADOptionalFeature [-Ide...
Get-ADAccountAuthorizationGrou...
Get-ADAccountResultantPassword...
Get-ADComputer -Filter <String...
To find a single domain controller, if you are not sure of one in your site, you can use the
discover switch on the Get-ADDomainController cmdlet. One thing to keep in mind is that
the discover parameter could return information from the cache. If you want to ensure that
a freshdiscover command is sent, use the forceDiscover switch in addition to the discover
switch. These techniques are shown here:
PS C:\> Get-ADDomainController -Discover
Domain
Forest
HostName
IPv4Address
IPv6Address
Name
Site
:
:
:
:
:
:
:
NWTraders.Com
NWTraders.Com
{HyperV.NWTraders.Com}
192.168.1.100
HYPERV
NewBerlinSite
Domain
Forest
HostName
IPv4Address
IPv6Address
Name
Site
:
:
:
:
:
:
:
NWTraders.Com
NWTraders.Com
{HyperV.NWTraders.Com}
192.168.1.100
HYPERV
NewBerlinSite
PS C:\>
52
CHAPTER 3
666498_book.indb 52
12/20/13 10:50 AM
ComputerObjectDN
DefaultPartition
Domain
Enabled
Forest
HostName
InvocationId
IPv4Address
IPv6Address
IsGlobalCatalog
IsReadOnly
LdapPort
Name
NTDSSettingsObjectDN
:
:
:
:
:
:
:
:
:
:
:
:
:
:
CN=HYPERV,OU=Domain Controllers,DC=NWTraders,DC=Com
DC=NWTraders,DC=Com
NWTraders.Com
True
NWTraders.Com
HyperV.NWTraders.Com
6835f51f-2c77-463f-8775-b3404f2748b2
192.168.1.100
True
False
389
HYPERV
CN=NTDS Settings,CN=HYPERV,CN=Servers,CN=NewBerlinSite,
CN=Sites,CN=Configuration,DC=NWTraders,DC=Com
OperatingSystem
: Windows Server 2008 R2 Standard
OperatingSystemHotfix
:
OperatingSystemServicePack :
OperatingSystemVersion
: 6.1 (7600)
OperationMasterRoles
: {SchemaMaster, DomainNamingMaster}
Partitions
: {DC=ForestDnsZones,DC=NWTraders,DC=Com, DC=DomainDnsZon
es,DC=NWTraders,DC=Com, CN=Schema,CN=Configuration,DC=N
WTraders,DC=Com, CN=Configuration,DC=NWTraders,DC=Com...}
ServerObjectDN
: CN=HYPERV,CN=Servers,CN=NewBerlinSite,CN=Sites,CN=Confi
guration,DC=NWTraders,DC=Com
ServerObjectGuid
: ab5e2830-a4d6-47f8-b2b4-25757153653c
Site
: NewBerlinSite
SslPort
: 636
PS C:\>
As shown in the preceding output, the server named Hyperv is a Global Catalog server.
It also holds the SchemaMaster and the DomainNamingMaster FSMO roles. It is running
Windows Server 2008 R2 Standard edition, which shows that the cmdlet works with downlevel versions of the operating system. The Get-ADDomainController cmdlet accepts a filter
parameter that can be used to perform a search and retrieve operation. It uses a special
search syntax that is discussed in the online help about files. Unfortunately, it does not accept
LDAP syntax.
666498_book.indb 53
CHAPTER 3
53
12/20/13 10:50 AM
Luckily, you do not have to learn the special filter syntax, because the Get-ADObject cmdlet
will accept a LDAP dialect filter. You can simply pipeline the results of the Get-ADObject cmdlet to the Get-ADDomainController cmdlet. This technique is shown here:
PS C:\> Get-ADObject -LDAPFilter "(objectclass=computer)" -searchbase "ou=domain
controllers,dc=nwtraders,dc=com" | Get-ADDomainController
ComputerObjectDN
DefaultPartition
Domain
Enabled
Forest
HostName
InvocationId
IPv4Address
IPv6Address
IsGlobalCatalog
IsReadOnly
LdapPort
Name
NTDSSettingsObjectDN
:
:
:
:
:
:
:
:
:
:
:
:
:
:
CN=HYPERV,OU=Domain Controllers,DC=NWTraders,DC=Com
DC=NWTraders,DC=Com
NWTraders.Com
True
NWTraders.Com
HyperV.NWTraders.Com
6835f51f-2c77-463f-8775-b3404f2748b2
192.168.1.100
ComputerObjectDN
DefaultPartition
Domain
Enabled
Forest
HostName
InvocationId
IPv4Address
IPv6Address
IsGlobalCatalog
IsReadOnly
LdapPort
Name
NTDSSettingsObjectDN
:
:
:
:
:
:
:
:
:
:
:
:
:
:
CN=DC1,OU=Domain Controllers,DC=NWTraders,DC=Com
DC=NWTraders,DC=Com
NWTraders.Com
True
NWTraders.Com
DC1.NWTraders.Com
fb324ced-bd3f-4977-ae69-d6763e7e029a
192.168.1.101
True
False
389
HYPERV
CN=NTDS Settings,CN=HYPERV,CN=Servers,CN=NewBerlinSite,
CN=Sites,CN=Configuration,DC=NWTraders,DC=Com
OperatingSystem
: Windows Server 2008 R2 Standard
OperatingSystemHotfix
:
OperatingSystemServicePack :
OperatingSystemVersion
: 6.1 (7600)
OperationMasterRoles
: {SchemaMaster, DomainNamingMaster}
Partitions
: {DC=ForestDnsZones,DC=NWTraders,DC=Com, DC=DomainDnsZones,
DC=NWTraders,DC=Com, CN=Schema,CN=Configuration,DC
=NWTraders,DC=Com, CN=Configuration,DC=NWTraders,DC=Com...}
ServerObjectDN
: CN=HYPERV,CN=Servers,CN=NewBerlinSite,CN=Sites,CN=Confi
guration,DC=NWTraders,DC=Com
ServerObjectGuid
: ab5e2830-a4d6-47f8-b2b4-25757153653c
Site
: NewBerlinSite
SslPort
: 636
OperatingSystem
54
CHAPTER 3
666498_book.indb 54
True
False
389
DC1
CN=NTDS Settings,CN=DC1,CN=Servers,CN=NewBerlinSite,CN=
Sites,CN=Configuration,DC=NWTraders,DC=Com
: Windows Serverr 2008 Standard without Hyper-V
12/20/13 10:50 AM
OperatingSystemHotfix
OperatingSystemServicePack
OperatingSystemVersion
OperationMasterRoles
Partitions
:
:
:
:
:
ServerObjectDN
ServerObjectGuid
Site
SslPort
:
:
:
Service Pack 2
6.0 (6002)
{PDCEmulator, RIDMaster, InfrastructureMaster}
{DC=ForestDnsZones,DC=NWTraders,DC=Com, DC=DomainDnsZones,
DC=NWTraders,DC=Com, CN=Schema,CN=Configuration,DC
=NWTraders,DC=Com, CN=Configuration,DC=NWTraders,DC=Com...}
CN=DC1,CN=Servers,CN=NewBerlinSite,CN=Sites,CN=Configur
ation,DC=NWTraders,DC=Com
80885b47-5a51-4679-9922-d6f41228f211
NewBerlinSite
636
PS C:\>
If it returns too much information, the Active Directory cmdlets work just like any other
Windows PowerShell cmdlet and therefore permit using the pipeline to choose the information you want to display. To obtain only the FSMO information, it comes down to two
commandsthree commands if you want to include importing the Active Directory module
in your count, or four commands if you need to make a remote connection to a domain
controller to run the commands. One cool thing about using Windows PowerShell remoting is that you specify the credentials that you need to run the command. If your normal
account is a standard user, you use an elevated account only when you require performing
actions with elevated rights. If you have already started the Windows PowerShell console with
elevated credentials, you can skip typing in credentials when you enter the remote Windows
PowerShell session (assuming that the elevated account also has rights on the remote server).
The first two commands seen here create a remote session on a remote domain controller
and load the ActiveDirectory module:
Enter-PSSession w8Server6
When the Active Directory module loads, you type a one-line command to get the Forest
FSMO roles, and you type another one-line command to get the domain FSMO roles. These
two commands are shown here:
Get-ADForest iammred.net | Format-Table SchemaMaster,DomainNamingMaster
Get-ADDomain iammred.net | format-table PDCEmulator,RIDMaster,InfrastructureMaster
That is ittwo or three one-line commands, depending on how you want to count. Even
at worst case, three one-line commands are much easier to type than 33 lines of code that
would be required if you did not have access to the Active Directory module. In addition, the
Windows PowerShell code is much easier to read and to understand. The commands and the
associated output from the Windows PowerShell commands appear in Figure 3-3.
666498_book.indb 55
CHAPTER 3
55
12/20/13 10:50 AM
After you have connected to the remote domain controller, you can use the Get-WmiObject
cmdlet to verify the operating system on that computer. This command and associated output are shown here:
[dc1]: PS C:\> Get-WmiObject win32_operatingsystem
SystemDirectory : C:\Windows\system32
Organization
:
BuildNumber
: 7601
RegisteredUser : Windows User
SerialNumber
: 55041-507-0212466-84005
Version
: 6.1.7601
Now you want to get information about the forest. To do this, you use the Get-ADForest
cmdlet. The output from the Get-ADForest cmdlet includes lots of great information, such as
the Domain Naming Master, Forest Mode, Schema Master, and Domain Controllers. This command and associated output appears here:
[dc1]: PS C:\> Get-ADForest
ApplicationPartitions : {DC=DomainDnsZones,DC=nwtraders,DC=com, DC=ForestDnsZones,DC
=nwtraders,DC=com}
CrossForestReferences : {}
56
CHAPTER 3
666498_book.indb 56
12/20/13 10:50 AM
DomainNamingMaster
Domains
ForestMode
GlobalCatalogs
Name
PartitionsContainer
RootDomain
SchemaMaster
Sites
SPNSuffixes
UPNSuffixes
:
:
:
:
:
:
:
:
:
:
:
DC1.nwtraders.com
{nwtraders.com}
Windows2008Forest
{DC1.nwtraders.com}
nwtraders.com
CN=Partitions,CN=Configuration,DC=nwtraders,DC=com
nwtraders.com
DC1.nwtraders.com
{Default-First-Site-Name}
{}
{}
Now, to obtain information about the domain, use the Get-ADDomain cmdlet. The command returns important information such as the location of the default domain controller OU,
the PDC emulator, and the RID master. The command and associated output are shown here:
[dc1]: PS C:\> Get-ADDomain
AllowedDNSSuffixes
ChildDomains
ComputersContainer
DeletedObjectsContainer
DistinguishedName
DNSRoot
DomainControllersContainer
DomainMode
DomainSID
ForeignSecurityPrincipalsContainer
Forest
InfrastructureMaster
LastLogonReplicationInterval
LinkedGroupPolicyObjects
LostAndFoundContainer
ManagedBy
Name
NetBIOSName
ObjectClass
ObjectGUID
ParentDomain
PDCEmulator
QuotasContainer
ReadOnlyReplicaDirectoryServers
ReplicaDirectoryServers
RIDMaster
SubordinateReferences
SystemsContainer
UsersContainer
:
:
:
:
:
:
:
:
:
:
:
:
:
:
{}
{}
CN=Computers,DC=nwtraders,DC=com
CN=Deleted Objects,DC=nwtraders,DC=com
DC=nwtraders,DC=com
nwtraders.com
OU=Domain Controllers,DC=nwtraders,DC=com
Windows2008Domain
S-1-5-21-909705514-2746778377-2082649206
CN=ForeignSecurityPrincipals,DC=nwtraders,DC=com
nwtraders.com
DC1.nwtraders.com
{CN={31B2F340-016D-11D2-945F-00C04FB984F9},CN
=Policies,CN=System,DC=nwtraders,DC=com}
: CN=LostAndFound,DC=nwtraders,DC=com
:
: nwtraders
: NWTRADERS
: domainDNS
: 0026d1fc-2e4d-4c35-96ce-b900e9d67e7c
:
: DC1.nwtraders.com
: CN=NTDS Quotas,DC=nwtraders,DC=com
: {}
: {DC1.nwtraders.com}
: DC1.nwtraders.com
: {DC=ForestDnsZones,DC=nwtraders,DC=com,
DC=DomainDnsZones,DC=nwtraders,DC=com,
CN=Configuration,DC=nwtraders,DC=com}
: CN=System,DC=nwtraders,DC=com
: CN=Users,DC=nwtraders,DC=com
From a security perspective, you should always check the domain password policy. To do
this, use the Get-ADDefaultDomainPasswordPolicy cmdlet. Things you want to pay attention
to are the use of complex passwords, minimum password length, password age, and password retention. You also need to check the account lockout policy. This policy is especially
666498_book.indb 57
CHAPTER 3
57
12/20/13 10:50 AM
important to review closely when inheriting a new network. Here is the command and associated output that does that very thing:
[dc1]: PS C:\> Get-ADDefaultDomainPasswordPolicy
ComplexityEnabled
: True
DistinguishedName
: DC=nwtraders,DC=com
LockoutDuration
: 00:30:00
LockoutObservationWindow
: 00:30:00
LockoutThreshold
: 0
MaxPasswordAge
: 42.00:00:00
MinPasswordAge
: 1.00:00:00
MinPasswordLength
: 7
objectClass
: {domainDNS}
objectGuid
: 0026d1fc-2e4d-4c35-96ce-b900e9d67e7c
PasswordHistoryCount
: 24
ReversibleEncryptionEnabled : False
The last things to check are the domain controllers themselves. To do this, use the Getcmdlet. This command returns important information, such as whether
the domain controller is read-only, a global catalog server, operations master roles held, and
operating system information. Here is the command and associated output:
ADDomainController
58
CHAPTER 3
666498_book.indb 58
12/20/13 10:50 AM
To produce a report is as easy as redirecting the output to a text file. These commands
gather the information discussed earlier in this section and store the retrieved information in
a file named AD_Doc.txt. The commands also illustrate that it is possible to redirect the information to a file stored in a network share.
Get-ADForest >> \\dc1\shared\AD_Doc.txt
Get-ADDomain >> \\dc1\shared\AD_Doc.txt
Get-ADDefaultDomainPasswordPolicy >> \\dc1\shared\AD_Doc.txt
Get-ADDomainController -Identity dc1 >>\\dc1\shared\AD_Doc.txt
Here is the code that will retrieve all of the sites. It uses the Get-ADObject cmdlet to search
the configuration naming context for objects that have the object class of site.
Get-ADObject -SearchBase (Get-ADRootDSE).ConfigurationNamingContext -filter "objectclass
-eq 'site'"
666498_book.indb 59
CHAPTER 3
59
12/20/13 10:50 AM
When you have the site you want to work with, you first change the DisplayName attribute. To do this, you pipeline the site object to the Set-ADOObject cmdlet. The Set-ADOObject
cmdlet allows me to set a variety of attributes on an object. This command is shown here.
(This is a single command that is broken into two pieces at the pipeline character.)
Get-ADObject -SearchBase (Get-ADRootDSE).ConfigurationNamingContext -filter "objectclass
-eq 'site'" | Set-ADObject -DisplayName CharlotteSite
When you have set the DisplayName attribute, you decide to rename the object itself.
To do this, you use another cmdlet called Rename-ADObject. Again, to simplify things, you
pipeline the site object to the cmdlet and you assign a new name for the site. This command
is shown here. (This is also a one-line command broken at the pipe.)
Get-ADObject -SearchBase (Get-ADRootDSE).ConfigurationNamingContext -filter "objectclass
-eq 'site'" | Rename-ADObject -NewName CharlotteSite
Managing users
To create a new Organizational Unit, you use the New-ADOrganizationalUnit cmdlet as shown
here:
New-ADOrganizationalUnit -Name TestOU -Path "dc=nwtraders,dc=com"
If you want to create a child Organizational Unit (OU), you use the Newcmdlet, but in the path, you list the location that will serve as the parent, as shown here:
ADOrganizationalUnit
If you want to make several child OUs in the same location, use the up arrow to retrieve
the previous command and edit the name of the child. You can use the home key to move to
the beginning of the line, the end key to move to the end of the line, and the left and right
arrow keys to find your place on the line so that you can edit it. A second child OU is created
here:
New-ADOrganizationalUnit -Name TestOU2 -Path "ou=TestOU,dc=nwtraders,dc=com"
To create a computer account in one of the newly created child Organizational Units,
you must type the complete path to the OU that will house the new computer account. The
New-ADComputer cmdlet is used to create new computer accounts in AD DS. In this example,
the TestOU1 OU is a child of the TestOU OU, and therefore, both OUs must appear in the
path parameter. Keep in mind that the path that is supplied to the path parameter must be
contained inside quotation marks, as shown here:
New-ADComputer -Name Test -Path "ou=TestOU1,ou=TestOU,dc=nwtraders,dc=com"
To create a user account, you use the New-ADUser cmdlet as shown here:
New-ADUser -Name TestChild -Path "ou=TestOU1,ou=TestOU,dc=nwtraders,dc=com"
60
CHAPTER 3
666498_book.indb 60
12/20/13 10:50 AM
Because there could be a bit of typing involved that tends to become redundant, you
might want to write a script to create the OUs at the same time that the computer and
user accounts are created. A sample script that creates OUs, users, and computers is the
UseADCmdletsToCreateOuComputerAndUser.ps1 script shown here.
UseADCmdletsToCreateOuComputerAndUser.ps1
Import-Module -Name ActiveDirectory
$Name = "ScriptTest"
$DomainName = "dc=nwtraders,dc=com"
$OUPath = "ou={0},{1}" -f $Name, $DomainName
New-ADOrganizationalUnit -Name $Name -Path $DomainName
-ProtectedFromAccidentalDeletion $false
For($you = 0; $you -le 5; $you++)
{
New-ADOrganizationalUnit -Name $Name$you -Path $OUPath
-ProtectedFromAccidentalDeletion $false
}
For($you = 0 ; $you -le 5; $you++)
{
New-ADComputer -Name
666498_book.indb 61
CHAPTER 3
61
12/20/13 10:50 AM
To create a new universal group, you need to change only the groupscope parameter value
as shown here:
New-ADGroup -Name TestGroup1 -Path "ou=TestOU,dc=nwtraders,dc=com" -groupScope universal
To add a user to a group, you must supply values for the identity parameter and for the
members parameter. The value that you use for the identity parameter is the name of the
group. You do not need to use the LDAP syntax of cn=groupname; you need to supply only
the name. Use ADSI Edit to examine the requisite LDAP attributes needed for a group in
ADSIEdit.
It is a bit unusual that the members parameter is named members and not member
because most Windows PowerShell cmdlet parameter names are singular and not plural. The
parameters are singular even when they accept an array of values (such as the computername
parameter). The command to add a new group named TestGroup1 to the UserGroupTest
group is shown here:
Add-ADGroupMember -Identity TestGroup1 -Members UserGroupTest
To remove a user from a group, use the Remove-ADGroupMember cmdlet with the name of
the user and group. The identity and the members parameters are required, but the command
will not execute without confirmation, as shown here:
PS C:\> Remove-ADGroupMember -Identity TestGroup1 -Members UserGroupTest
Confirm
Are you sure you want to perform this action?
Performing operation "Set" on Target "CN=TestGroup1,OU=TestOU,DC=NWTraders,DC=Com".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):
y
PS C:\>
If you are sure that you want to remove the user from the group and that you want to suppress the query, you use the confirm parameter and assign the value $false to it. The problem
is that you will need to supply a colon between the parameter and $false value.
NOTE The use of the colon after the confirm parameter is not documented, but the tech-
You need the ability to suppress the confirmation prompt to be able to use the Removecmdlet in a script. The first thing the RemoveUserFromGroup.ps1 script does
is load the Active Directory module. When the module is loaded, the Remove-ADGroupMember
cmdlet is used to remove the user from the group. To suppress the confirmation prompt, the
confirm:$false command is used. The RemoveUserFromGroup.ps1 script is shown here.
ADGroupMember
62
CHAPTER 3
666498_book.indb 62
12/20/13 10:50 AM
RemoveUserFromGroup.ps1
import-module activedirectory
Remove-ADGroupMember -Identity TestGroup1 -Members UserGroupTest -Confirm:$false
Creating a user
Now create a new user in Active Directory. You will name the user ed. The command to
create a new user is simple; it is New-Aduser and the user name. The command to create a
disabled user account in the users container in the default domain is shown here:
new-aduser -name ed
When the preceding command that creates a new user completes, nothing is returned to
the Windows PowerShell console. To check to ensure that the user is created, use the GetAduser cmdlet to retrieve the user object. This command is shown here:
Get-aduser ed
When you are certain that your new user is created, you decide to create an organizational
unit to store the user account. The command to create a new organizational unit off the root
of the domain is shown here:
new-ADOrganizationalUnit scripting
Just like the previously used New-Aduser cmdlet, nothing returns to the Windows
PowerShell console. If you use the Get-ADOrganizationalUnit cmdlet, you must use a different
methodology. A simple Get-AdOrganizationalUnit command returns an error; therefore, you
use an LDAPFilter parameter to find the OU. The command using the LDAPFilter parameter to
find my newly created OU is shown here:
Get-ADOrganizationalUnit LDAPFilter "(name=scripting)"
Now that you have a new user and a new OU, you need to move the user from the users
container to the newly created scripting OU. To do that, you use the Move-ADObject cmdlet.
You first get the distinguishedname attribute for the scripting OU and store it in a variable
called $oupath. Next, you use the Move-ADObject cmdlet to move the ed user to the new OU.
The trick here is that where the Get-AdUser cmdlet can find a user with the name of ed, the
Move-ADObject cmdlet must have the distinguishedname of the ed user object to move it.
The error that occurs when not supplying the distinguishedname appears in the figure that
follows. You could use the Get-AdUser cmdlet to retrieve the distinguishedname in a similar
method as you did with the scripting OU.
The next thing you need to do is to enable the user account. To do this, you need to assign
a password to the user account. The password must be a secure string. To do this, you can use
the ConvertTo-SecureString cmdlet. By default, warnings display about converting text to a
666498_book.indb 63
CHAPTER 3
63
12/20/13 10:50 AM
secure string, but these prompts are suppressible by using the force parameter. Here is the
command you use to create a secure string for a password:
$pwd = ConvertTo-SecureString -String "P@ssword1" -AsPlainText Force
Now that you have created a secure string to use for a password for my user account, you
call the Set-ADAccountPassword cmdlet to set the password. Because this is a new password,
you need to use the newpassword parameter. In addition, because you do not have a previous
password, you use the reset parameter. This command is shown here:
Set-ADAccountPassword -Identity ed -NewPassword $pwd Reset
After the account has a password, you can enable the account. To do this, you use the
cmdlet and specify the user name to enable. This command is shown here:
Enable-ADAccount
Enable-ADAccount -Identity ed
As with the previous commands, none of the cmdlets return any information. To ensure
that you have actually enabled the ed user account, you use the Get-ADUser cmdlet. In the
output, you are looking for the value of the enabled property. The enabled property is a
Boolean, so expect the value to be true.
NOTE Many network administrators who spend the majority of their time working with
Active Directory import the Active Directory module via their Windows PowerShell profile.
This way, they never need to worry about the initial performance hit that occurs due to
autoloading the Active Directory module.
The Search-ADAccount command and the associated output are shown here:
[w8server6]: PS C:\> Search-ADAccount -LockedOut
AccountExpirationDate
DistinguishedName
Enabled
LastLogonDate
LockedOut
Name
ObjectClass
ObjectGUID
PasswordExpired
PasswordNeverExpires
64
CHAPTER 3
666498_book.indb 64
:
:
:
:
:
:
:
:
:
:
CN=kimakers,OU=test,DC=iammred,DC=net
True
1/24/2012 8:40:29 AM
True
kimakers
user
d907fa99-cd08-435f-97de-1e99d0eb485d
False
False
12/20/13 10:50 AM
SamAccountName
SID
UserPrincipalName
: kimakers
: S-1-5-21-1457956834-3844189528-3541350385-1608
: [email protected]
[w8server6]: PS C:\>
You can unlock the locked out user account as wellassuming that you have permission.
In Figure 3-5, you attempt to unlock the user account with an account that is a normal user,
and an error arises.
NOTE People are often worried about Windows PowerShell from a security perspective.
Windows PowerShell is only an application, and therefore a user cannot do anything that
they do not have the rights or permission to accomplish. This is a case in point.
If your user account does not have admin rights, you need to start Windows PowerShell
with an account that has the ability to unlock a user account. To do this, you right-click the
Windows PowerShell icon while holding down the Shift key; this allows you to select Run As
Different User from the quick action menu.
When you start Windows PowerShell back up with an account that has rights to unlock
users, the Active Directory module needs to load once again. You then check to ensure that
you can still locate the locked out user accounts. After you have proven you can do that, you
pipeline the results of the Search-ADAccount cmdlet to the Unlock-ADAccount cmdlet. A quick
check ensures that you have unlocked all the locked out accounts. The series of commands is
shown here:
Search-ADAccount LockedOut
Search-ADAccount -LockedOut | Unlock-ADAccount
Search-ADAccount LockedOut
FIGURE 3-5Using the Active Directory module to find and to unlock user accounts.
666498_book.indb 65
CHAPTER 3
65
12/20/13 10:50 AM
NOTE Keep in mind that the command Search-ADAccount -LockedOut | UnlockADAccount will unlock every account that you have permission to unlock. In most cases,
you will want to investigate prior to unlocking all locked out accounts. If you do not want
to unlock all locked out accounts, use the confirm switch to be prompted prior to unlocking an account.
If you do not want to unlock all users, you use the confirm parameter from the Unlockcmdlet. For example, you first check to see what users are locked out by using the
Search-ADAccount cmdletbut you do not want to see everything, only their name. Next,
you pipeline the locked out users to the Unlock-ADAccount cmdlet with the confirm parameter.
You are then prompted for each of the three locked out users; choose to unlock the first and
third users, but not the second user. You then use the Search-ADAccount cmdlet one last time
to ensure that the second user is still locked out.
ADAccount
Not only is the command a single line of code, but it is also a single line of readable code.
You get users from AD DS; you use a filter that looks for the enabled property set to false.
You also specify that you want to query a server named dc3 (the name of one of the domain
controllers on my network). The command and the associated output appear in Figure 3-6.
66
CHAPTER 3
666498_book.indb 66
12/20/13 10:50 AM
If you want to work with a specific user, you can use the identity parameter. The identity parameter accepts several things: distinguishedname, sid, guid, or SamAccountName.
Probably the easiest one to use is the SamAccountName. This command and associated
output are shown here:
PS C:\Users\ed.IAMMRED>
Get-ADUser -Server dc3 -Identity teresa
DistinguishedName : CN=Teresa Wilson,OU=Charlotte,DC=iammred,DC=net
Enabled
: True
GivenName
: Teresa
Name
: Teresa Wilson
ObjectClass
: user
ObjectGUID
: 75f12010-b952-4d3-9b22-3ada7d26eed8
SamAccountName
: Teresa
SID
: S-1-5-21-1457956834-3844189528-3541350385-1104
Surname
: Wilson
UserPrincipalName : [email protected]
To use the DistinguishedName value for the identity parameter, you need to supply it
inside a pair of quotation markseither single or double. This command and associated
output are shown here:
PS C:\Users\ed.IAMMRED>
Get-ADUser -Server dc3 -Identity 'CN=Teresa Wilson,OU
=Charlotte,DC=iammred,DC=net'
DistinguishedName : CN=Teresa Wilson,OU=Charlotte,DC=iammred,DC=net
Enabled
: True
GivenName
: Teresa
Name
: Teresa Wilson
ObjectClass
: user
ObjectGUID
: 75f12010-b952-4d3-9b22-3ada7d26eed8
SamAccountName
: Teresa
SID
: S-1-5-21-1457956834-3844189528-3541350385-1104
Surname
: Wilson
UserPrincipalName : [email protected]
It is not necessary to use quotation marks when using the SID for the value of the identity
parameter. This command and associated output are shown here:
PS C:\Users\ed.IAMMRED>
Get-ADUser -Server dc3 -Identity S-1-5-21-14579568343844189528-3541350385-1104
DistinguishedName
Enabled
GivenName
Name
ObjectClass
ObjectGUID
SamAccountName
SID
Surname
UserPrincipalName
666498_book.indb 67
:
:
:
:
:
:
:
:
:
:
CN=Teresa Wilson,OU=Charlotte,DC=iammred,DC=net
True
Teresa
Teresa Wilson
user
75f12010-b952-4d3-9b22-3ada7d26eed8
Teresa
S-1-5-21-1457956834-3844189528-3541350385-1104
Wilson
[email protected]
CHAPTER 3
67
12/20/13 10:50 AM
Again, you can also use ObjectGUID for the identity parameter value. It does not require
quotation marks either. This command and associated output are shown here:
PS C:\Users\ed.IAMMRED>
Get-ADUser -Server dc3 -Identity 75f12010-b952-4d3-9
b22-3ada7d26eed8
DistinguishedName : CN=Teresa Wilson,OU=Charlotte,DC=iammred,DC=net
Enabled
: True
GivenName
: Teresa
Name
: Teresa Wilson
ObjectClass
: user
ObjectGUID
: 75f12010-b952-4d3-9b22-3ada7d26eed8
SamAccountName
: Teresa
SID
: S-1-5-21-1457956834-3844189528-3541350385-1104
Surname
: Wilson
UserPrincipalName : [email protected]
If you want to change the base of the search operations, use the searchbase parameter.
The searchbase parameter accepts an LDAP style of naming. The following command changes
the search base to the TestOU:
Get-ADUser -Filter * -SearchBase "ou=TestOU,dc=nwtraders,dc=com"
When using the Get-ADUser cmdlet, only a certain subset of user properties are displayed
(10 properties to be exact). These properties will be displayed when you pipeline the results
to Format-List and use a wildcard and the force parameter, as shown here:
PS C:\> Get-ADUser -Identity bob | format-list -Property * -Force
DistinguishedName
Enabled
GivenName
Name
ObjectClass
ObjectGUID
SamAccountName
SID
Surname
UserPrincipalName
PropertyNames
PropertyCount
:
:
:
:
:
:
:
:
:
:
:
:
CN=bob,OU=TestOU,DC=NWTraders,DC=Com
True
bob
bob
user
5cae3acf-f194-4e07-a466-789f9ad5c84a
bob
S-1-5-21-3746122405-834892460-3960030898-3601
[email protected]
{DistinguishedName, Enabled, GivenName, Name...}
10
PS C:\>
68
CHAPTER 3
666498_book.indb 68
12/20/13 10:50 AM
Anyone who knows very much about Active Directory Domain Services (AD DS) knows that
there are certainly more than 10 properties associated with a user object. If you try to display
a property that is not returned by the Get-ADUser cmdlet, such as the whenCreated property,
an error is not returnedthe value of the property is not returned. This is shown here:
PS C:\> Get-ADUser -Identity bob | Format-List -Property name, whenCreated
name
: bob
whencreated :
The whenCreated property for the user object has a valueit just is not displayed.
However, suppose you were looking for users who had never logged on to the system?
Suppose you used a query such as the one seen here, and you were going to base a delete
operation on the results? The results could be disastrous.
PS C:\> Get-ADUser -Filter * | Format-Table -Property name, LastLogonDate
name
LastLogonDate
---------------Administrator
Guest
krbtgt
testuser2
ed
SystemMailbox{1f05a927-a261-4eb4-8360-8...
SystemMailbox{e0dc1c29-89c3-4034-b678-e...
FederatedEmail.4c1f4d8b-8179-4148-93bf-...
Test
TestChild
<results truncated>
To retrieve a property that is not a member of the default 10 properties, you must select
it by using the property parameter. The reason that Get-ADUser does not automatically return
all properties and their associated values is because of performance reasons on large networksthere is no reason to return a large dataset when a small dataset will perfectly suffice.
To display the name and the whenCreated date for the user named bob, the following command can be used:
PS C:\> Get-ADUser -Identity bob -Properties whencreated | Format-List -Property name,
whencreated
name
: bob
whencreated : 6/11/2010 8:19:52 AM
PS C:\>
666498_book.indb 69
CHAPTER 3
69
12/20/13 10:50 AM
To retrieve all of the properties associated with a user object, use the wildcard * for the
properties parameter value. You would use a command similar to the one shown here:
Get-ADUser -Identity kimakers -Properties *
Both the command and the results associated with the command to return all user properties are shown in Figure 3-7.
To produce a listing of all the users and their last logon date, you can use a command
similar to the one shown here. This is a single command that might wrap the line, depending
on your screen resolution.
Get-ADUser -Filter * -Properties "LastLogonDate" |
sort-object -property lastlogondate -descending |
Format-Table -property name, lastlogondate -AutoSize
The output produces a nice table. Both the command and the output associated with the
command to obtain the time a user last logged on are shown in Figure 3-8.
FIGURE 3-8Using the Get-ADUser cmdlet to identify the last logon times for users.
70
CHAPTER 3
666498_book.indb 70
12/20/13 10:50 AM
Write tools, not scripts is one of my favorite phrases from the Windows
PowerShell community. When I had just started to write some Windows PowerShell
code, I was (and still am!) crazy about one-liners.
The ease with which the pipeline allows you to connect commands to each other
and make them work together were unheard of in the VBS world.
But then I got a customer who wanted me to leave some code with them when I
left. So I did, and only one week later, I got a call from that customer, in panic, saying that my script had deleted half their Active Directory!
I asked them to send me the code of the script. After only a few seconds, I noticed
that this wasnt my code. There was a whole lot more in there that didnt come from
me. So I connected to my home environment and looked in the backup I had made
of all the scripts and documentation I had left with the customer, and yes, the script
I had left them had a lot less code in there. So someone had changed my script!
Luckily, this customer had the Active Directory Recycle Bin enabled, so restoring the
objects in Active Directory wasnt that hard. But for me, this was a wake-up call.
Sign your scripts! Or at least make sure that you can verify the integrity of your
scripts.
I also found that the person who changed my script, and basically was the cause
of the problem, was a member of the service desk at that company. This is where
write tools, not scripts comes into play.
So I rewrote my script, added a GUI, and signed it. This way, the help desk would
have a nice clickable interface, and the script itself would be safe from malicious
editors causing all kinds of issues. Because there were a whole bunch of scripts,
Ive created a module for them called <CompanyName>Administration. To finish things off, Ive introduced them to the concept of a centralized store for their
modules.
For me, this was a learning curve, and these days I prefer a six steps approach:
1. Log everything; what it does and who executes it.
2. Support the common parameters, such as Whatif and -Confirm.
3. Create an interface for the appropriate usera command line for people who
understand PowerShell and a GUI for those who dont.
4. Sign your script!
666498_book.indb 71
CHAPTER 3
71
12/20/13 10:50 AM
Additional resources
72
CHAPTER 3
666498_book.indb 72
12/20/13 10:50 AM
666498_book.indb 674
12/20/13 10:52 AM
Index
Symbols
* (asterisk), as wildcard character, 24
` (backtick) character, for line continuation, 305
: (colon), confirm parameter for $false value, 62
{ } (curly brackets)
for ForEach-Object cmdlet, 191
for function code block, 117
for opening and closing script block, 242
pairing comment with closing, 282, 305
$_ automatic variable, 255, 435
$? automatic variable, for testing errors, 188
$ (dollar sign), variable name and, 341342
$_ variable, for current object, 220
! (not) operator, 188, 346
( ) (parentheses), in functions, 116
; (semicolon), to separate commands on single line, 10
<# and #> for comment tag, 287289
! SET keyword, to preface variable assignments, 572
A
Abort, Retry, Ignore dialog box, 132
Abs method of System.Math class, 180
Abstract Syntax Tree (AST), 480
abstract WMI classes, 32
access denied message, 83
Access Is Denied error message, 561
Access property of Win32_LogicalDisk class, 249
AccountDomainSid method of SecurityIdentifier
class,87
account lockout policy, 57
Acos method of System.Math class, 180
Active Directory
cmdlets,13
documenting,5659
675
666498_book.indb 675
12/20/13 10:52 AM
Add-RegistryValue function
looping,119
pipelining to Get-WmiObject cmdlet, 344
$arycomputer variable, 219220
ASCII file. See alsotext files
.ddf file as, 190
Asin method of System.Math class, 180
as operator, 87, 93
Association classes, 3541
exploring returned, 40
finding, 31
asterisk (*), as wildcard character, 24
AST parser, 484486
Atan2 method of System.Math class, 180
Atan method of System.Math class, 180
authentication,152
AuthenticationType property of WindowsIdentity
object,84
authorized verb list, warning to check, 317
Autoexec.bat file, 141
automation interface, 7582
automation of routine tasks, 7374
Availability property of Win32_LogicalDisk class, 249
B
background job
checking status, 640
Windows PowerShell as, 82
backslash, escaping, 158
backspace (`b), 93
backtick (`) character, for line continuation, 305
backtick n, 93
backtick r, 93
backtick t (`t), 265
BackUpFiles.ps1 script, 278280
backup of scripts, 547
backups of domain controllers, for script testing, 471
BadGetRandomObject.ps1 script, 154
BadParam.ps1 script, 348
BadScript.ps1 script, 573581
basename property of System.Io.FileInfo class, 322
BasicFunctions.psm1 module, 331333
batch file, 4
Begin block in filter, 274
Begin parameter, 270
Belle, Chris, 229, 483484
BigMul method of System.Math class, 180
676
666498_book.indb 676
12/20/13 10:52 AM
cmdlets
C
cabinet files, 183
adding files to, 184
closing,184
expanding,186
calling functions, 238
Canastreiro, Lus, 101102, 159
CanStartStopService method of Shell.Application
object,186
Caption property of Win32_LogicalDisk class, 249
Carter, Marc, 329
CascadeWindows method of Shell.Application object,186
case-sensitive operator (-ceq), 114
677
666498_book.indb 677
12/20/13 10:52 AM
CmdLineArgumentsTime.ps1 script
entering multiple, 10
exporting history, 203205
locating,607
overriding existing, 117118
running in script pane, 609
setting breakpoint on, 593595
in text file, 196
CommandType property of System.Management.Automation.ScriptInfo object, 178
comment-based help, 289294, 477
comments, 256, 468
documentation from, 481483
documenting nested structures with, 305306
in functions, 117
internal version number in, 525528
multiple-line, 277, 287288
one-line, 277287, 303304
creating,288289
pairing with curly bracket, 282
rules for writing, 295310
adding during development process, 296297
avoiding useless information, 302
consistency in header information, 298299
international audience and, 297298
on document deficiencies, 300301
prerequisite information, 299300
reason for code, 303
updating for updated script, 295296
on script changes, 527
standard set of keywords for, 306307
on strange items in code, 307308
Commercial Certificate Authority, 524
common classes, 169
Common Language Runtime (CLR), vs. .NET Framework,101
ComObject parameter, 182
CompareTo method of SecurityIdentifier class, 86
compatibility of scripts, version control and, 523
Complete-Transaction cmdlet, 650
complicated constructors, 153154
Component help tag, 290
compressed file, unzipping, 665
Compressed property of Win32_LogicalDisk class, 249
computers
account creation, 60
ping to identify accessible, 402403
ConfigManagerErrorCode property of
Win32_LogicalDisk class, 249
678
666498_book.indb 678
12/20/13 10:52 AM
database
D
data
handling large amounts, 166168
presentation functions separated from gathering,264265
testing scripts against known, 471
database
for script logging, 542
679
666498_book.indb 679
12/20/13 10:52 AM
data types
of scripts, 229
testing script connecting to, 467468
data types
aliases for, 253254
incorrect,423429
DateTime object, 435, 445
.ddf file
as ASCII file, 190
creating,189
debugging. See alsoerrors
basics,559567
breakpoints for, 586587
setting,587595
PowerShell cmdlets for, 585603
quitting session, 588
recommendations for, 585
script-level tracing for, 568572
Set-PSDebug cmdlet for, 567585
stepping through script, 572581
syntax errors, 560
debug mode, exiting, 600
debug parameter, 16, 183, 460462, 562564
$DebugPreference variable, 177, 184, 562
Debug-Process cmdlet, 650
DebugRemoteWMISession.ps1 script, 562563
$debug variable, 188
checking presence, 192
default script execution policy, 492
default value for parameter, 247, 398399
default WMI namespace, 27
Definition property System.Management.Automation.
ScriptInfo object, 178
DefragAnalysis method, 219, 220
DefragAnalysisReport.ps1 script, 219, 221
defragmentation report, redirection to produce, 220
Dekens, Luc, 565567
DeleteScriptingRegistryKey.ps1 script, 225
deleting
breakpoints,601
read-only cmdlet, 115
remnants of completed jobs, 636
risk of deleting wrong script version, 527
snippets,613
DemoAddOneFilter.ps1 script, 272
DemoAddOneFunction.ps1 script, 272273
DemoAddOneR2Function.ps1 script, 273
DemoConsoleBeep.ps1 script, 302
DemoConsoleBeep2.ps1 script, 303
680
666498_book.indb 680
12/20/13 10:52 AM
ErrorRecord class
E
EjectPC method of Shell.Application object, 186
elevated permissions, 83
email
output to, 387388
sending logging information by, 551
Enable-ADAccount cmdlet, 64
enabled property, for user account, 64
Enable-PSBreakpoint cmdlet, 586, 599, 601, 650
Enable-PSRemoting function, 627628
Encoding parameter, 540
Encrypting File System (EFS), 363
End block in block, 274
End parameter, 221, 270
Enterprise Certificate Authority, 524
681
666498_book.indb 681
12/20/13 10:52 AM
errors
errors
constructors and, 154
divide-by-zero,597
from handling large amounts of data, 166168
Invalid parameter, 122
from Invoke-Command, 197
from job script block, 638
logic,564565
looking for, 438439
from missing closing bracket, 282
from multiple instances for inputobject parameter,3839
from not supplying distinguishedname, 63
from null value as argument, 345346
from PowerShell workflow, 647
runtime,560564
syntax,560
testing, $? automatic variable for, 188
from Throw statement, 346
from type constraint deviation, 254255
from version incompatibility, 155
WinRM and, 628629
writing to log file, 468
from wrong placement of Param, 348
error stack, clearing, 435
-ErrorVariable parameter, 16
escaping backslash, 158
$etime variable, 436
evaluating scripts, 479480
event log, 509510
custom,555
logging to, 552555
monitoring,552
Example help tag, 290
-examples argument, 24
examples, in cmdlet documentation, 281
Exec method of WshShell object, 130
exiting debug mode, 600
Exit-PSSession cmdlet, 650
Expand-Cab function, 223
ExpandCab.ps1 script, 189
ExpandEnvironmentStrings method of WshShell object,130
expanding cabinet file, 186
ExpectingInput property of System.Management.Automation.InvocationInfo class, 178
Explore method of Shell.Application object, 186
ExplorerPolicy method of Shell.Application object, 186
F
fan-out commands, 205208
Farr, Ian, 524525, 541, 546547
Favorites folder, path to, 128
feedback, on help documentation, 281
file hashes, counting, 8
$filepath property, 221
File resource provider, 660
FileRun method of Shell.Application object, 186
files
output to, 382383
searching for string pattern, 243244
splitting output to screen and, 383387
filesystemobject, 152
FileSystem property of Win32_LogicalDisk class, 249
FilterHasMessage.ps1 script, 274
filter parameter of Get-CimInstance cmdlet, 33, 39
filters, 270275
to remove folders from cabinet file collection, 191
for WMI classes by qualifier, 3033
FilterToday.ps1 script, 274
FindAll method of DirectorySearcher object, 209
FindComputer method of Shell.Application object, 186
FindDisabledUserAccounts.ps1 script, 295296
FindFiles method of Shell.Application object, 186
finding
Association classes, 31
document files, 260
FSMO role holders, 5056
unused user accounts, 6872
user accounts, 6466
682
666498_book.indb 682
12/20/13 10:52 AM
Get-BiosArray1.ps1 script
G
__GENUS property of Win32_Logical Disk class, 250
Get-ADDefaultDomainPasswordPolicy cmdlet, 57
Get-ADDomain cmdlet, 57
Get-ADDomainController cmdlet, 5253, 58
Get-ADForest cmdlet, 56
GetAdminFunction.ps1 script, 98
Get-ADObject cmdlet, 59
Get-ADOrganizationalUnit cmdlet, 63, 216
Get-ADRootDSE cmdlet, 59
Get-ADUser cmdlet, 63-64, 66
wildcard for filter parameter, 68
Get-Alias cmdlet, 25, 112-113, 124125, 650
Get-AllowedComputerAndProperty.ps1 script, 408
Get-AllowedComputer function, 407408
Get-AllowedComputer.ps1 script, 404406
Get-ASTScriptProfile.ps1 script, 480
Get-AuthenticodeSignature cmdlet, 504
GetBinaryForm method of SecurityIdentifier class, 86
Get-BiosArgsCheck2.ps1 script, 346
Get-BiosArgsTrap1.ps1 script, 347
Get-BiosArray1.ps1 script, 343
683
666498_book.indb 683
12/20/13 10:52 AM
Get-BiosArray2.ps1 script
684
666498_book.indb 684
12/20/13 10:52 AM
Get-WmiObject cmdlet
685
666498_book.indb 685
12/20/13 10:52 AM
Get-WmiProvider function
to retrieve Win32_NetworkAdapterConfiguration
WMI class instances, 261
to retrieve Win32_OperatingSystem WMI class
instance,237
to verify operating system, 56
for WMI class listing, 121, 170
Get-WmiProvider function, 417418, 422
Get-WmiProviderFunction.ps1 script, 422423
Get-WMIProviders.ps1 script, 168169
Get-WSManInstance cmdlet, 618
gip,5
global security group, creating, 61
global variable, 390392
namespace in, 392393
Goude, Niklas, 513514, 646
graphical applications, testing, 458459
Group-Object cmdlet, 234236
Group Policy
assigning scripts from within, 513
script execution policy deployment with, 499500
script execution policy modified with, 495
script execution policy setting with, 412413
Set the default source path for Update-Help, 20
Group Policy Object (GPO)
for logon/logoff script, 507508
for PowerShell deployment, 7
Group Policy Preferences, scheduled task for UpdateHelp,2021
Group Policy templates (ADM files), 502
Group resource provider, 660, 669671
groups
adding user, 62
determining match, 93
removing user from, 62
Groups property of WindowsIdentity object, 84, 8586
GUIs, 105, 337
Gusev, Vasily, 599601
H
hash of password, storing in text file, 368369
hash table of permissible values, 429
HasMessage filter, 274
header for script, 278, 477478
HelloUserTimeworkflow.ps1 script, 645
HelloUserworkflow.ps1 script, 644
Helmick, Jason, 56
I
identity parameter, 6768
for Get-ADDomainController cmdlet, 53
IEEERemainder method of System.Math class, 181
686
666498_book.indb 686
12/20/13 10:52 AM
Klindt, Todd
J
jobs in PowerShell, 634641
creating,20
Join-DtcDiagnosticResourceManager cmdlet, 619
Join-Path cmdlet, 127-128, 189190, 285, 322, 533, 544
Jones, Don, 26, 516, 521, 585
K
k command (debugging), 595
Kearney, Sean, 23
$key variable, 78
keywords, standard set for comments, 306307
Kinect for Windows, 409
Klindt, Todd, 108109
687
666498_book.indb 687
12/20/13 10:52 AM
lab environment
L
lab environment, 470
language statement, breakpoint and, 593
LastErrorCode property of Win32_LogicalDisk class, 249
LDAP attributes, 62
LDAPFilter parameter, 63
LDAP search filter syntax, 209210
resources,230
LDIFDE,471473
learning,106
to script, 230
Windows PowerShell, 109
legacy code, migrating to PowerShell, 79
like operator, 89
Limit-EventLog cmdlet, 619, 624
line continuation character, 191, 305
line number, setting breakpoint on, 588589
Line property of System.Management.Automation.
InvocationInfo class, 178
Link help tag, 290
List command, 596, 600
loaded modules, listing, 312
loading modules, 108
$localappdata environment variable, 126
local computer
BIOS information from, 33
storing scripts in, 515
workflow on, 644645
LocalMachine, as default for execution policy setting,503
locked-out users, locating, 6466
Log10 method of System.Math class, 181
LogChartProcessWorkingSet.ps1 script, 537, 538539,
542
LogEvent method of WshShell object, 130
log files
appending to, 532, 536539
Application log, 554555
networked,548549
from script testing, 456457
from Start-Transcript function, 468470
writing errors to, 468
logging
benefits, 550552
designing approach for, 532542
to event log, 552555
for building maintainable scripts, 541542
M
Maheu, Georges, 162, 193
mailing list, 74
Major part of operating system version, 102
major version of script, 527
MakeCab.exe utility, 189
makecab.expandcab object, 185
makecab.makecab object, 183, 185
Managed Object Format (MOF) file, 660661
MandatoryParameter.ps1 script, 400
mandatory parameters, 350351, 353, 399400
manifest for module, 333
match operator, 8990, 93
MaximumComponentLength property of Win32_LogicalDisk class, 249
$MaximumHistoryCount variable, 135
Max method of System.Math class, 181
Maxvalue property, 362
Mayer, Keith, 76
McGlone, Ashley, 4546
MD5, hash creation with, 8
MeasureAddOneFilter.ps1 script, 271
MeasureAddOneR2Function.ps1 script, 273
Measure-Command cmdlet, 448449, 451455
Measure-Object cmdlet, 113
688
666498_book.indb 688
12/20/13 10:52 AM
namespaces
N
named parameters
multiple,122126
vs. positional, 239
name parameter, dollar sign ($) and, 128
Name property
of Win32_LogicalDisk class, 249
of WindowsIdentity object, 84
names
for functions, 237
verb-noun convention for, 116
for jobs, 636
for parameters, 62
for returned job object, 638
NameSpace method of Shell.Application object, 187,
188
__NAMESPACE property of Win32_Logical Disk
class,250
namespaces, 27, 163166
generating list for machine, 164166
689
666498_book.indb 689
12/20/13 10:52 AM
O
ObjectGUID for the identity parameter, 68
objects,163166
storing,166167
OffsetInLine property of System.Management.Automation.InvocationInfo class, 178
one-line comments, 303304
On Error Resume Next statement (VBScript), 427
Open method of Shell.Application object, 187
OpenPasswordProtectedExcel.ps1 script, 372
OpenPasswordProtectedWord.ps1 script, 372373
operating system
scripting requirements, 102106
verifying for remote domain controller, 56
versions, 102, 104
compatibility issues, 155158
690
666498_book.indb 690
12/20/13 10:52 AM
passwords
P
Package resource provider, 660
package.xml file, 222
paging
more function for, 116
Windows PowerShell ISE and, 25
paging parameter, 380
parallel activities in workflow, 645648, 651652
691
666498_book.indb 691
12/20/13 10:52 AM
storing
Active Directory Domain Services for, 366367
registry for, 365366
in script, 363364
text file for, 364365
for user accounts, 63
pasting functions into Function library script, 244
path,499
adding script directory to, 293294
to Favorites folder, 128
length on command line, 133
in profile, 134135
to Windows Update Log, 126127
path parameter, for Get-Content cmdlet, 196
__PATH property of Win32_Logical Disk class, 250
$path variable, 77, 434
pause in script execution. Seebreakpoints
PDF document, creating, 376
performance, process block and, 273274
permissions,513
errors from, 561
listing required in documentation, 281
NTFS File System (NTFS), 363
to unlock user account, 65
persistence points in workflow, 643
persisting a workflow, 652658
Pfeiffer, Mike, 535536
ping command, 195, 402403, 629
PingComputers.ps1 script, 358359
PingIpAddress.ps1 script, 359360
pinning Windows PowerShell
to desktop taskbar, 605
to Start screen and taskbar, 14
$pinToStart,14
PinToStartAndTaskBar.ps1 script, 14
$pinToTaskBar,14
pipeline, 71, 352, 393, 435, 444445, 446450
function in, vs. filter, 270272
for job object, 640
performance improvements from technique, 220
scope of, 356
PipelineLength property of System.Management.Automation.InvocationInfo class, 178
PipelinePosition property of System.Management.Automation.InvocationInfo class, 178
PipelineVariable parameter, 355
piping ipconfig / results to text files, 10
PI property of System.Math class, 182
692
666498_book.indb 692
12/20/13 10:52 AM
Q
qualifier, dynamic, 32
query, Active Directory, 208217
R
Rahim, Ibrahim Abdul, 439, 455, 458
range operator (..), 113
readability of scripts, 309310
Read-Host cmdlet, 238, 367, 373
AsSecureString parameter, 368
ReadHostQueryDrive.ps1 script, 373374
ReadHostSecureStringQueryWmi.ps1 script, 368
reading text file, 196203
read mode, 590592
read-only aliases, making, 114115
read-only cmdlet, deleting, 115
read-only variables, 126
readwrite mode, 591592
Receive-DtcDiagnosticTransaction cmdlet, 620
Receive-Job cmdlet, 621, 635, 638
Keep,641
Receive-PSSession cmdlet, 621
RecursiveWMINameSpaceListing.ps1 script, 164166
Recycle Bin, for Active Directory, 71
redirection operators, 531
ReferenceEquals method of System.Math class, 181
RefreshMenu method of Shell.Application object, 187
693
666498_book.indb 693
12/20/13 10:52 AM
694
666498_book.indb 694
12/20/13 10:52 AM
scripting pitfalls
S
Sajid, Osama, 602
SamAccountName for Get-ADUser cmdlet, 67
SAPIEN Technologies, 529
saveas method of Word.Document object, 227
Save-Help cmdlet, 20
695
666498_book.indb 695
12/20/13 10:52 AM
Script-level scope
696
666498_book.indb 696
12/20/13 10:52 AM
697
666498_book.indb 697
12/20/13 10:52 AM
Stewart, Bill
T
tab character, 265
Tabdilio, Mark, 275276
tab expansion, 561, 610611
for module name completion, 316317
Tanh method of System.Math class, 182
Tan method of System.Math class, 182
taskbar, pinning Windows PowerShell to, 14
tasks, automation of routine, 7374
TechNet Script Center, 26, 41, 109
Tee-Object cmdlet, 383385, 543546, 550
variable parameter for, 385
temporary file
for log file, 548
698
666498_book.indb 698
12/20/13 10:52 AM
TypeText method
reading,196203
redirecting cmdlet output to, 59
width parameter for output, 540
Throw statement, 188, 346
TileHorizontally method of Shell.Application object,187
TileVertically method of Shell.Application object, 187
TimeSpan object, 450
time stamp
converting,394
in log file, 469, 533
TODO: tags, 307
ToggleDesktop method of Shell.Application object, 187
Tokenize method of PSParser class, 484486
Token property of WindowsIdentity object, 84
ToString method, 86, 87
Trace-Command cmdlet, 650
$trace variable, 538
tracing, script-level, 568572
tracking
changes with version control, 523
script changes, 527528
transactions, registry modification with, 176
TranscriptBios.ps1 script, 469470
transcript tool in PowerShell, 630631
Translate method, 86-87, 93
trapping operating system version, 160161
Trap statement, 254-255, 346347, 410
TrayProperties method of Shell.Application object, 187
TroubleShoot.bat script, 10
troubleshooting. See alsodebugging; errors; testing
scripts
logging for, 537, 541
missed closing bracket, 242
version control and, 523
Truman, Jeff, 1516
Truncate method of System.Math class, 182
Trusted Internet zone, 515
Trusted Sites zone, adding script share to, 495
Try/Catch/Finally construction, 347, 410412
Tsaltas, Dean, 280
Turn On Script Execution Group Policy setting, 139
two-letter aliases, 113
Tyler, Jonathan, 99100
type constraints for parameters, 122123, 253255
type mismatch error message, 343
TypeText method, 226
699
666498_book.indb 699
12/20/13 10:52 AM
unapproved verbs
U
unapproved verbs, 317318
UnboundArguments property of System.Management.
Automation.InvocationInfo class, 178
Undefined execution policy, 503
UndoMinimizeALL method of Shell.Application object,187
Undo-Transaction cmdlet, 650
uninitialized variable, 582
universal group, creating, 62
Universal Naming Convention (UNC) path, 548
Universal Naming Convention (UNC) shares, Internet
zone and, 495
Unlock-ADAccount cmdlet, 65
confirm parameter, 66
unlocking user accounts, 6466
Unrestricted script execution policy, 140, 493, 499, 502
unused sessions, removing, 213
unused user accounts, finding, 6872
unzipping compressed file, 665
Update-Help cmdlet, 17
UpdateHelpTrackErrors.ps1 script, 1819
updating help, 1719
UseADCmdletsToCreateOuComputerAndUser.ps1
script,61
use case scenario, 397
UseGetMemberOf.ps1 script, 91, 9295
User Account Control (UAC), 83, 408
user accounts
creating,60
disabled,63
finding, 6668
enabling,6364
finding and unlocking, 6466
finding unused, 6872
user-defined snippets, 612
removing,613614
user interfaces, automating tests in, 459
user management in Active Directory module, 6063
user objects
properties for, 69
retrieving all properties associated with, 70
whenCreated property, 69
user preferences for restricted execution policy, 139
%UserProfile% location, 330
User property of WindowsIdentity object, 84
User resource provider, 660, 669
V
ValidateCount parameter attribute, 360
ValidateLength parameter attribute, 360
ValidateNotNullOrEmpty parameter attribute, 361-362
ValidateNotNull parameter attribute, 361
ValidatePattern attribute, 358359, 360
ValidateRange parameter, 360, 430
ValidateRange.ps1 script, 357
ValidateScript parameter attribute, 360
ValidateSet parameter attribute, 361
validating parameter input, 356361
ValueFromPipelineByPropertyName parameter attribute argument, 353
ValueFromPipeline parameter attribute argument, 353
ValueFromRemainingArguments parameter attribute
argument,353
Value method of SecurityIdentifier class, 87
values, passing to function, 238
$value variable, 78
VariableNotFound error message, 342
variables
assigning returned job object to, 638639
assigning value to, 126
changing value in suspended script, 579
CIM instance in, 35
creating,126133
global,390392
names,145
dollar sign and, 341342
property selection in, 35
! SET keyword to preface assignments, 572
setting breakpoint on, 589593
uninitialized,582
VBScript, 159, 394
classic function example, 233
700
666498_book.indb 700
12/20/13 10:52 AM
W
Wait-Job cmdlet, 639
Walker, Jason, 166168
Wbemtest.exe,415
Web Application Services Platform (WASP), 459
Web Services Description Language (WSDL), 254, 544
web services, testing, 455
websites, testing, 458
whatif parameter, 11, 16, 247, 460, 464467
whenCreated property, for user object, 69
701
666498_book.indb 701
12/20/13 10:52 AM
running,605611
script pane, 608609
snippets,611614
syntax error detection, 560
tab expansion and Intellisense, 610611
for testing, 440
Windows PowerShell remoting. Seeremoting
Windows PowerShell Web Access (PWA), 26
Windows PowerShell workflow, 643. See alsoworkflow
WindowsPrincipal class, IsInRole method of, 97
WindowsProcess resource provider, 660
Windows Remote Management (WinRM), 626634
WindowsSecurity method of Shell.Application object,187
Windows Server 2012, installing Active Directory module on, 47
Windows Server 2012 R2, 6
running in core mode, 3
Windows Update, 222
Windows Update Log, storing path to, 126127
Windows Vista
user Personal folder on, 142
user rights, 155
WindowSwitcher method of Shell.Application object,187
Windows Workflow Foundation, 643
WinRM (Windows Remote Management), 626634
WMI providers
missing,415423
searching registry for registration, 420421
WMI Query Language (WQL), 170
Windows PowerShell syntax and, 158
Word.Application object, 226
Word.Document object, saveas method, 227
workarounds,157
workflow, 516
activities in, 648652
checkpoint in, 652655
cmdlets
as activities, 649
disallowed from core modules, 650
as InlineScript activities, 650651
cool features, 657
for parallel PowerShell, 645648
on local computer, 644645
parallel activities, 651652
persistence points in, 643
reasons to use, 643645
702
666498_book.indb 702
12/20/13 10:52 AM
Zone.Identifier tag
requirements,644
sequence activity in, 656658
workflow keyword, 644
working directory, changing, 3
Wouters, Jeff, 71
Wrap parameter, 208
WriteBiosInfoToWord.ps1 script, 298299
Write-Debug cmdlet, 177, 190, 460, 561-562, 565
for progress indicator, 188
Write-EventLog cmdlet, 555, 623-624
Write-Host cmdlet, 265, 347, 389, 592, 650
write mode for breakpoint, 589590
Write-Output cmdlet, 247
Write-Path function, 241
Write verb, 238
Write-Verbose cmdlet, 176, 420, 421422, 464, 585
WshNetwork object, mapping network drives with, 533
WshShell object, 79, 128130
New-Object cmdlet for creating, 77
SpecialFolders property, 129
$wshShell variable, 77
WshSpecialFolders object, 129
WS-Management Protocol, 626
WS-Management (WSMan) cmdlets
remoting with, 82
X
XML file, 395
for console file, 15
debugger to dump variables into, 600
exporting commands to, 203
exporting Lync server configuration to, 375
exporting to, 386
formatted for screen output, 377378
for snippet, 612
XPath,395
XQuery statement, 395
Z
Zone.Identifier tag, 494
703
666498_book.indb 703
12/20/13 10:52 AM