Quantcast
Channel: Hey, Scripting Guy! Blog
Viewing all 3333 articles
Browse latest View live

Playing with the AD: Drive for Fun and Profit

0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using the AD: drive to explore Active Directory Domain Services.

Hey, Scripting Guy! Question Hey, Scripting Guy! I will confess that I love using the Active Directory module for Windows PowerShell. I love the way I can use Windows PowerShell to create new users or to easily search for and find users and other stuff. What I do not get is the drive that the Active Directory module creates. I mean, what good is it? Every time I try to change to my domain “folder,” all I get is an error. I guess that it is used under the covers for something, but it seems a shame that I cannot use it too. Not sure if there is a question here other than, “Can I actually use the AD: drive?” If the answer here is, “Yes,” I need a follow up question, “How?” Thanks for listening and for all the good work you do.

—RR

Hey, Scripting Guy! Answer Hello RR,

Microsoft Scripting Guy, Ed Wilson, is here. This morning I am sipping a cup of English Breakfast tea and listening to Abba. I was looking at some of the pictures Teresa and I took while we were in Stockholm, and for some reason Abba songs kept coming to my mind. When this happens, it seems that all I can do to extinguish the tune is to flood it. I am also thinking about, “I am your Scripting King…” Hmm…

Understanding the AD: drive

You get the Active Directory module as part of the Remote Server Administration Tools for Windows 8. One of the cool features in Windows PowerShell 3.0 is when I use a cmdlet, Windows PowerShell automatically loads the module that contains the cmdlet if it is not already present. Autoloading is great.

Therefore, when I use Get-ADComputer, Windows PowerShell automatically loads the Active Directory module. However, if the Active Directory module is not already loaded, attempting to set my working location to the AD: drive generates an error. This is shown here.

PS C:\> sl ad:

sl : Cannot find drive. A drive with the name 'ad' does not exist.

At line:1 char:1

+ sl ad:

+ ~~~~~~

    + CategoryInfo          : ObjectNotFound: (ad:String) [Set-Location], DriveNotFoundException

    + FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.SetLocationCommand

Load the Active Directory module to use the drive

After you import the Active Directory module, the AD: drive becomes available. I can then set my working location to the AD: drive. I can also use Get-ChildItem to retrieve the contents. This is shown here.

PS C:\> sl ad:

PS AD:\> dir

 

Name                 ObjectClass          DistinguishedName

----                 -----------          -----------------

iammred              domainDNS            DC=iammred,DC=net

Configuration        configuration        CN=Configuration,DC=iammred,DC=net

Schema               dMD                  CN=Schema,CN=Configuration,DC=iammred,D..

DomainDnsZones       domainDNS            DC=DomainDnsZones,DC=iammred,DC=net

ForestDnsZones       domainDNS            DC=ForestDnsZones,DC=iammred,DC=net

Unfortunately, what I see on the AD: drive is not what you need to use to actually interact with the drive. This leads to confusion. Therefore, when I attempt to set my location to the iammred container, an error arises. This is shown here.

PS AD:\> sl iammred

sl : Cannot find path 'AD:\iammred' because it does not exist.

At line:1 char:1

+ sl iammred

+ ~~~~~~~~~~

    + CategoryInfo          : ObjectNotFound: (AD:\iammred:String) [Set-Location],ItemNotFoundException

    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.SetLocationCommand

The error is a bit misleading because obviously iammred does exist. I can prove that it exists by piping the object to the Where-Object as shown here.

PS AD:\> dir | ? name -eq 'iammred'

 

Name                 ObjectClass          DistinguishedName

----                 -----------          -----------------

iammred              domainDNS            DC=iammred,DC=net

I use the up arrow, and send the output to the Format-List cmdlet to view all of the information in my search for a hint. The output from the command is shown here.

Image of command output

Change my working location to the domain

I decide to use the Set-Location cmdlet to change my working location to the actual domain. To do this, I specify the DistinguishedNameattribute. Because the components of the name separate via commas, I place the string in quotation marks. When I have my working location on the domain drive, I use the Get-ChildItem cmdlet to produce an output. These commands are shown here.

PS AD:\> sl "dc=iammred,dc=net"

PS AD:\dc=iammred,dc=net> dir

The commands and the output associated with the commands are represented in the image that follows.

Image of command output

To change location to the child containers, the first portion of the distinguished name is required. Therefore attempting to set the location to the Users container fails when attempted as follows.

sl users

It also fails when I attempt to connect to OU=Users as seen here. This is understandable because Usersis a container and not an organizational unit (OU).

sl "ou=users"

When I use Set-Location to change the working location to cn=users, does the command work? This is shown here.

PS AD:\dc=iammred,dc=net> sl "cn=users"

PS AD:\cn=users,dc=iammred,dc=net>

I can use the .. shortcut to move up a level in the hierarchy as shown here.

PS AD:\cn=users,dc=iammred,dc=net> sl ..

PS AD:\dc=iammred,dc=net> dir

I use the same technique to change to the Charlotte OU. This command is shown here.

PS AD:\dc=iammred,dc=net> sl "ou=charlotte"

PS AD:\ou=charlotte,dc=iammred,dc=net>

To move to the root of the C: drive from the AD: drive, use the Set-Location cmdlet and specify the C: drive. This technique is shown here.

PS AD:\ou=charlotte,dc=iammred,dc=net> sl c:\

PS C:\>

From the root of the C: drive, to go back to the Charlotte OU, I use the full path as shown here.

PS C:\> sl "AD:\ou=charlotte,dc=iammred,dc=net"

PS AD:\ou=charlotte,dc=iammred,dc=net>

When I navigate, I like to use Push and Pop. So, from the Charlotte OU, I use the Push-Location cmdlet to store the path to my current location, and then I change to the C: drive This is shown here.

PS AD:\ou=charlotte,dc=iammred,dc=net> push-location

PS AD:\ou=charlotte,dc=iammred,dc=net> sl c:

PS C:\>

Next, I use Pop-Location to return me to the Charlotte OU. This technique is shown here.

PS C:\> Pop-Location

PS AD:\ou=charlotte,dc=iammred,dc=net>

Create a new Windows PowerShell drive for a favorite OU

If I find myself spending a lot of time in the Charlotte OU, I do not want to deal with a lot of typing to change to the OU. So I can create a new Windows PowerShell Drive only for Charlotte. First, I need to know the name of the provider. I get this by using the Get-PSProvider cmdlet. This is shown here.

PS C:\> Get-PSProvider

 

Name                 Capabilities                    Drives

----                 ------------                    ------

Alias                ShouldProcess                   {Alias}

Environment          ShouldProcess                   {Env}

FileSystem           Filter, ShouldProcess, Crede... {C, D, E}

Function             ShouldProcess                   {Function}

Registry             ShouldProcess, Transactions     {HKLM, HKCU, HKCR}

Variable             ShouldProcess                   {Variable}

ActiveDirectory      Include, Exclude, Filter, Sh... {AD}

It is as I suspected. Now I create my new Windows PowerShell drive by using the New-PSDrive cmdlet. The only thing that is tricky is the value for Root. I copied the string that I used earlier with Set-Location, and it worked perfectly here.

PS C:\> New-PSDrive -Name Charlotte -PSProvider ActiveDirectory -Root "AD:\ou=charlot

te,dc=iammred,dc=net"

 

Name           Used (GB)     Free (GB) Provider      Root

----           ---------     --------- --------      ----

Charlotte                              ActiveDire... //RootDSE/ou=charlotte,dc=ia...

Remember, I now have a Windows PowerShell drive, so I need the colon at the end of the drive name to navigate there. This is shown here.

PS C:\> sl charlotte:

PS Charlotte:\>

When I am on the drive, I can use standard cmdlets to work with the data. Here I use dir(alias for Get-ChildItem) to obtain a list of all members of the Charlotte OU.

PS Charlotte:\> dir

Name                 ObjectClass          DistinguishedName

----                 -----------          -----------------

ED-PC                computer             CN=ED-PC,OU=Charlotte,DC=iammred,DC=net

ed wilson            user                 CN=ed wilson,OU=Charlotte,DC=iammred,DC...

EDLT                 computer             CN=EDLT,OU=Charlotte,DC=iammred,DC=net

HYPERV2              computer             CN=HYPERV2,OU=Charlotte,DC=iammred,DC=net

Regular User         user                 CN=Regular User,OU=Charlotte,DC=iammred...

Sample User          user                 CN=Sample User,OU=Charlotte,DC=iammred,...

SQL                  user                 CN=SQL,OU=Charlotte,DC=iammred,DC=net

Teresa Wilson        user                 CN=Teresa Wilson,OU=Charlotte,DC=iammre...

RR, that is all there is to using the AD: drive. Active Directory Week will continue tomorrow when I will talk about searching Active Directory by using the AD: drive.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 


PowerTip: Avoid Loading the AD: Drive with the Active Directory Module

0
0

Summary: Learn how to avoid loading the default AD: drive when you load the Active Directory module for Windows PowerShell.

Hey, Scripting Guy! Question How can I avoid creating the default AD: drive when I import the Active Directory module for Windows PowerShell?

Hey, Scripting Guy! Answer Use the ENV drive and set the ADPS_LoadDefaultDrive variable to 0. Add the following line to your Windows PowerShell profile to make the change “permanent.”

$Env:ADPS_LoadDefaultDrive = 0 

Find Active Directory User Info with the PowerShell Provider

0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about how to use the Windows PowerShell provider to find user information in Active Directory.

Hey, Scripting Guy! Question Hey, Scripting Guy! I often need to find information in Active Directory, but I do not like having to write LDAP queries. To me, it is soooo last century—I mean, Fred Flintstone used to write LDAP queries. I love the way that...

—CH

Hey, Scripting Guy! Answer Hello CH,

Microsoft Scripting Guy, Ed Wilson, is here. CH, I know what you mean. I loved my first computer, but I have no desire to go back to using the CPM operating system. Luckily, with the Active Directory module provider, I have direct access to an AD: drive. This makes it easy to use Windows PowerShell to explore. Because of the Active Directory module provider, and the way that Windows PowerShell providers work, I need no special Active Directory Domain Services (AD DS) knowledge. In fact, I can use the same commands that I would use if I was exploring the file system, the registry, the environmental variables, or even the variable drive. Windows PowerShell abstracts the underlying data and permits me to use a file system analogy to work with the data.

Note   This is the second in a series of blogs about working with the Active Directory module provider. You should definitely read Playing with the AD: Drive for Fun and Profit prior to reading today’s blog because I am going to build on everything that went before.

Filtering by using the Where-Object cmdlet

The cool thing about the AD: drive is the ability to use standard Windows PowerShell cmdlets to find and to filter the AD DS data. In the example that follows, I import the Active Directory module, create a Windows PowerShell drive that exposes Charlotte organizational unit (OU) information, and filter out only the users from the OU. The commands is shown here (ipmo is an alias for Import-Module, sl is an alias for Set-Location, dir is an alias for Get-Childitem, and ? is an alias for Where-Object).

ipmo activedirectory

New-PSDrive -PSProvider activedirectory -Name charlotte -Root "AD:\ou=Charlotte,DC=Iammred,DC=net"

sl charlotte:

dir

dir | ? objectclass -eq user

The commands and the output associated with the commands are shown in the image that follows.

Image of command output

Finding a specific user

To find a specific user, I again use Where-Object. I have a couple of choices to use when filtering for the contact. I can use the Nameproperty or the DistinguishedNameproperty. Because the Nameproperty is shorter and requires less typing, I use that one as shown here.

PS charlotte:\> dir | ? name -match 'ed wilson'

 

Name                 ObjectClass          DistinguishedName

----                 -----------          -----------------

ed wilson            user                 CN=ed wilson,OU=Charlotte,DC=iammred,DC...

If I would like to directly access the user object instead of filtering to find the user object, I need to use the DistinguishedName attribute. But it is not as bad as it might sound. This is because the DistinguishedName property becomes the path to the object.

I discovered this when I tried to use Get-Item to access the user object. Normally, a property such as Namewould what I would expect to use to find an object. In fact, that is what I did in my Where-Object command–I filtered on a value for the Nameattribute. When I use the name of the user in my Get-Item command to retrieve a user, an error message appears. This command and the message are shown here.

PS charlotte:\> Get-Item 'ed wilson'

Get-Item : Cannot find path 'charlotte:\ed wilson' because it does not exist.

At line:1 char:1

+ Get-Item 'ed wilson'

+ ~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : ObjectNotFound: (charlotte:\ed wilson:String) [Get-Item], ItemNotFoundException

    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand

Note that the error message is ObjectNotFound, and the FullyQualifiedErrorIdis PathNotFound. Therefore, Get-Item is attempting to look for a path to an object and is not finding it. In fact, whenever I use Get-Item, I must specify a path to the object. For example, if I want to retrieve a log file, I specify the path. This is shown here.

PS C:\> Get-Item C:\fso\20110314.log

If I am already in the C:\fso folder, a period can be used to take the place of the C:\fso portion of the path—but still, I must specify a path. This is shown here.

PS C:\fso> get-item .\20110314.log

If I think of OU=Charlotte, DC=Iammred, and DC=NET as folders (or directories), the file system analogy works. The DistinguishedName attribute is the full path to the object. Therefore, if I am in the OU=Charlotte folder, I only need to specify the last portion of the DistinguishedName attribute. This technique is shown here.

PS charlotte:\> Get-Item .\'cn=ed wilson'

 

Name                 ObjectClass          DistinguishedName

----                 -----------          -----------------

ed wilson            user                 cn=ed wilson,ou=Charlotte,DC=Iammred,DC...

Luckily, the Active Directory module provider does not require the .\—therefore, I can drop it as shown in this example.

PS charlotte:\> Get-Item 'cn=ed wilson'

 

Name                 ObjectClass          DistinguishedName

----                 -----------          -----------------

ed wilson            user                 cn=ed wilson,ou=Charlotte,DC=Iammred,DC...

Filtering directly by using Get-Item

Because the Get-Item cmdlet supports the use of the Filterparameter, I can easily create a filter to find a specific user. All I need to do is to specify a value for the Nameattribute and use a wildcard character for the path. This technique is shown here when I am on the Charlotte Windows PowerShell drive.

PS charlotte:\> Get-Item -Filter "name=ed wilson" -Path *

 

Name                 ObjectClass          DistinguishedName

----                 -----------          -----------------

ed wilson            user                 CN=ed wilson,ou=Charlotte,DC=Iammred,DC...

The cool thing is that I can even filter for properties not normally returned. So for example, I can find users who have a city value of Charlotte (the lowercaseL is the LDAP attribute). This technique is shown here.

PS charlotte:\> Get-Item -Filter "l=charlotte" -Path *

 

Name                 ObjectClass          DistinguishedName

----                 -----------          -----------------

ed wilson            user                 CN=ed wilson,ou=Charlotte,DC=Iammred,DC...

Teresa Wilson        user                 CN=Teresa Wilson,ou=Charlotte,DC=Iammre...

Performing a recursive search by using Get-ChildItem

Perhaps I want to search for users that have a city value of Charlotte, but I do not know in which OU they reside. To do this, I can use the Get-ChildItem cmdlet and use the Recurseparameter.

PS AD:\dc=iammred,dc=net> Get-ChildItem -Filter "l=charlotte" -Path * -Recurse

 

Name                 ObjectClass          DistinguishedName

----                 -----------          -----------------

ed wilson            user                 CN=ed wilson,OU=Charlotte,dc=iammred,dc...

Teresa Wilson        user                 CN=Teresa Wilson,OU=Charlotte,dc=iammre...

MyNewUser            user                 CN=MyNewUser,OU=MyTestOU,dc=iammred,dc=net

CH, that is all there is to using the Active Directory module provider in Windows PowerShell to find user information. Active Directory Week will continue tomorrow when I will talk about finding and modifying user information.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Easily Obtain the AD DS Default Password Policy

0
0

Summary: Learn how to use Windows PowerShell to obtain the default password policy for Active Directory Domain Services in Windows Server 2012.

Hey, Scripting Guy! Question How can I easily find the Active Directory Domain Services (AD DS) default password policy by using Windows PowerShell?

Hey, Scripting Guy! Answer Use the Get-ADDefaultDomainPasswordPolicy cmdlet from the Remote Server Administration Tools for Windows 8.

 

Use PowerShell to Find Non-Default User Properties in AD

0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell and the Active Directory module provider to find non-default AD DS user properties.

Hey, Scripting Guy! Question Hey, Scripting Guy! I need to find information about users such as office location, and phone number that is not returned by the Active Directory module provider by default. How do I do this?

—DP

Hey, Scripting Guy! Answer Hello DP,

Microsoft Scripting Guy, Ed Wilson, is here. Today is what is officially called the calm after the storm. Massive thunderstorms ripped through Charlotte last night, knocking out power and phones. Hey, that is OK; but dude, I lost my Internet connection in the process. Major bummer. With battery backups, a generator, and what-not, I can handle bad weather—as long as it does not knock out my Internet connection. I do not have a backup ISP provider. Hey, where I live, I was lucky to get the one I have. Oh, well.

Guess what? I was just told that Windows PowerShell MVP and honorary Scripting Guy, Sean Kearney, will be presenting at Microsoft TechEd in New Orleans and in Madrid. Way to go Sean! By the way, there are two more days until the $300 discount expires.

Note   This is the third in a series of blog postings about using the Active Directory module provider. The first blog is an overview called Playing with the AD: Drive for Fun and Profit.The second blog is Find Active Directory User Information with the PowerShell Provider, in which I talk about how to use the Windows PowerShell provider to find user information in Active Directory.

Quick review

To create the Charlotte: PSDrive (points to the Charlotte organizational unit or OU), I ran the following commands. (Obviously, you need to change the commands to point to an OU and a domain that exist on your system.)

PS C:\> ipmo activedirectory

PS C:\> New-PSDrive -Name charlotte -PSProvider activedirectory -Root "AD:\ou=charlot

te,dc=iammred,dc=net"

 

Name           Used (GB)     Free (GB) Provider      Root

----           ---------     --------- --------      ----

charlotte                              ActiveDire... //RootDSE/ou=charlotte,dc=ia...

 

PS C:\> sl charlotte:

PS charlotte:\>

Getting properties of the user

I might think that to easily see all of the information associated with the Ed Wilson user, I can pipe the output to the Format-List (fl is an alias) cmdlet as shown here.

PS charlotte:\> dir | ? name -match 'ed wilson' | fl *

The command and the output associated with the command are shown in the image that follows.

Image of command output

The problem with this approach is that only four properties of the user return. The four default properties are DistinguishedName, Name, ObjectClass, and ObjectGUID. However, a quick look in Active Directory Users and Computers reveals that there are many more attributes and values available. This is shown here.

Image of menu

What about Get-ADUser?

Due to performance reasons, the Get-ADUser cmdlet does not return all properties of a user object. It returns the following properties:

PS C:\> Get-ADUser 'cn=ed wilson,ou=charlotte,dc=iammred,dc=net' | select -expand propertynames

DistinguishedName

Enabled

GivenName

Name

ObjectClass

ObjectGUID

SamAccountName

SID

Surname

UserPrincipalName

Therefore, if I want to access additional attributes and their associated values, I need to specifically request the attributes I desire. Unfortunately, the attribute names bear little relationship to the names that appear in Active Directory Users and Computers. The best way to find the required attributes is to use ADSI Edit. In modern versions of ADSI Edit, there is a view that shows only attributes that contain values.
Consequently, it is fairly easy to match the actual name of the Active Directory attribute and the name that appears in Active Directory Users and Computers.

Note   In my Windows PowerShell 3.0 Step by Step book, I have a chapter that includes screenshots that map the Active Directory Users and Computers interface to the actual AD Attribute names.

The ADSI Edit property sheet for the Ed Wilson user object is shown here.

Image of menu

Use Get-ItemProperty to get other attributes

So what is the trick to obtaining additional attributes from the user object beyond the four default properties returned by Get-Item? One approach is to use the Get-ItemProperty cmdlet. This technique is shown here where I retrieve the city (lower case L) attribute for the user.

PS charlotte:\> Get-ItemProperty -Path '.\CN=ed wilson' -Name l

l            : Charlotte

PSPath       : Microsoft.ActiveDirectory.Management\ActiveDirectory:://RootDSE/CN=ed

                wilson,ou=Charlotte,DC=Iammred,DC=net

PSParentPath : Microsoft.ActiveDirectory.Management\ActiveDirectory:://RootDSE/ou=Ch

               arlotte,DC=Iammred,DC=net

PSChildName  : CN=ed wilson

PSDrive      : charlotte

PSProvider   : Microsoft.ActiveDirectory.Management\ActiveDirectory

Use Get-Item to get other attributes

I do not have to use the Get-ItemProperty cmdlet to retrieve other attributes from a user object. I can use the Get-Item cmdlet and type in an array of attributes in the Propertiesparameter. This technique is shown here where I add in the city (l) and the phone number (telephoneNumber) to the command.

PS charlotte:\> get-item -Path "cn=ed wilson" -Properties l, telephonenumber

 

PSPath             : Microsoft.ActiveDirectory.Management\ActiveDirectory:://RootDSE

                     /cn=ed wilson,ou=charlotte,dc=iammred,dc=net

PSParentPath       : Microsoft.ActiveDirectory.Management\ActiveDirectory:://RootDSE

                     /ou=charlotte,dc=iammred,dc=net

PSChildName        : cn=ed wilson

PSDrive            : charlotte

PSProvider         : Microsoft.ActiveDirectory.Management\ActiveDirectory

PSIsContainer      : True

distinguishedName  : cn=ed wilson,ou=charlotte,dc=iammred,dc=net

l                  : Charlotte

name               : ed wilson

objectClass        : user

objectGUID         : bb10b5a2-58d7-4f8a-ab10-2ee84fc7cb58

telephoneNumber    : 555-555-1212

PropertyNames      : {distinguishedName, l, name, objectClass...}

AddedProperties    : {}

RemovedProperties  : {}

ModifiedProperties : {}

PropertyCount      : 7

Use Get-Item and retrieve all of the attributes

I can also use a wildcard character (*) to retrieve all of the attributes for my user object. The command is shown here.

PS charlotte:\> get-item -Path "cn=ed wilson" -Properties *

The command and its associated output are shown in the following image.

Image of command output

DP, that is all there is to using the Active Directory module provider to find information about users. Active Directory Week will continue tomorrow when I will talk about modifying user attributes.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Use PowerShell to Determine AD Forest Mode

0
0

Summary: Learn how to use Windows PowerShell and the Active Directory module to determine the AD DS forest mode.

 Hey, Scripting Guy! Question How can I use Windows PowerShell to determine the AD DS forest mode?

Hey, Scripting Guy! Answer Use the Get-ADForest cmdlet from the Active Directory module for Windows PowerShell and use the ForestMode property:

(Get-ADForest).ForestMode

Use the PowerShell AD Provider to Modify User Attributes

0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using the Windows PowerShell Active Directory module provider to modify user attributes in AD DS.

Hey, Scripting Guy! Question Hey, Scripting Guy! Just searching for users, or filtering for them, is not entirely all that useful. For me, I need to be able to make changes based on that search or filter. Is this easily done, or is it a real pain to do?

—DR

Hey, Scripting Guy! Answer Hello DR,

Microsoft Scripting Guy, Ed Wilson, is here. Yesterday, I received word that my latest appearance on Blain Barton’s TechNet Radio Podcast is now live. In fact, Devon Musgrave at Microsoft Press wrote a cool blog about it. Blain and I talked about how certification literally changed our lives. The appearance was fun to do, and the discussion should be fun to listen to in addition to informational.
Check it out: Author news: Ed Wilson on how certification changed his life.

Note  This is the fourth blog in a series about using the Active Directory module.

Find users that need modification

Suppose there are several users in an OU that have a specific attribute that needs to be changed. This may because of merging departments or in the case of a corporate buyout. In the following image, the office location of the user needs to be changed.

Image of menu

This particular task begins with finding the user, and it can be a bit frustrating. After attempting to find a user object with an office in Raleigh that resides in the Charlotte OU, I was about to give up. Then I decided to look up the user in ADSI Edit. Here is what I found out.

Image of results

The property that appears as Officein ADUC is called PhysicalDeliveryOfficeName. Without a quick peek at ADSI Edit, I would never have discovered that one! So now, all is groovy.

Note  I am using a PS Drive called Charlotte that is homed on the Charlotte OU. I explained how to create it in Playing with the AD: Drive for Fun and Profit.

Keep in mind that I do not use spaces with this filtering technique. Although it does not generate an error, the following command does not find any users either.

PS charlotte:\> Get-Item -Filter "physicaldeliveryofficename = Raleigh" -Path *

PS charlotte:\>

So I need to remove the spaces. The following command finds the two users I need to modify. The cool thing about using Get-Item here is that if more than one item matches the filter, it returns all matching objects. Here is the command I use.

PS charlotte:\> Get-Item -Filter "physicaldeliveryofficename=Raleigh" -Path *

 

Name                 ObjectClass          DistinguishedName

----                 -----------          -----------------

Regular User         user                 CN=Regular User,ou=charlotte,dc=iammred...

Sample User          user                 CN=Sample User,ou=charlotte,dc=iammred,...

 

PS charlotte:\>

Modify the user object with Set-ItemProperty

Now that I know what filter I need to use and I have verified that I can find the users that need updating, it is time to perform the actual modification. The cool thing here is that I use the Set-ItemProperty cmdlet to make the modifications. By using Set-ItemProperty, it becomes really easy to modify the users whose office changed from Raleigh to Charlotte. In fact, the command is so easy to use that it contains its own Filterparameter.

Therefore, all I need to do is to copy the filter I used with the Get-Item cmdlet and paste it into the Filterparameter. Because I am potentially going to make a bunch of changes, I decided to use the WhatIfparameter first to tell me exactly what the command will do. The following command illustrates using WhatIfand the Filterparameters with the Set-ItemProperty cmdlet to model a potential change to user objects in AD DS. The output generated by the WhatIfparameter lets me know the two users who will receive the modification.

PS charlotte:\> Set-ItemProperty -Filter "physicaldeliveryofficename=Raleigh" -Path *

 -Name physicaldeliveryofficename -Value Charlotte -WhatIf

What if: Performing operation "Set" on Target "CN=Regular User,ou=charlotte,dc=iammred,dc=net".

What if: Performing operation "Set" on Target "CN=Sample User,ou=charlotte,dc=iammred,dc=net".

PS charlotte:\>

Now that I see the two users who will receive the changed office locations are the same two users I found by using the Get-Item cmdlet, I can be reasonably certain that the command will perform what I want it to do. Therefore, I use the up arrow to retrieve my previous command, and this time I erase the –WhatIfportion of the command. (I always use WhatIfat the end of a cmdlet call so that it is easy to delete when it comes time to run the actual command.) As shown here, nothing returns from running the command.

PS charlotte:\> Set-ItemProperty -Filter "physicaldeliveryofficename=Raleigh" -Path *

 -Name physicaldeliveryofficename -Value Charlotte

PS charlotte:\>

I use the up arrow a couple of times and retrieve my previous Get-Item command to see if any users still have offices in Raleigh. As shown here, the command finds no users—they have all been changed.

PS charlotte:\> Get-Item -Filter "physicaldeliveryofficename=Raleigh" -Path *

PS charlotte:\>

OK. One more check…seeing is believing. Let me verify that the office is changed on one of the users I found earlier. Yep, the user office location is in fact changed from Raleigh, as shown here.

Image of menu

DR, that is all there is to using modifying user objects with the Windows PowerShell Active Directory provider. Active Directory Week will continue tomorrow when I will talk about further use of Windows PowerShell techniques with the Active Directory module provider.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Use PowerShell to See Status of AD Optional Features

0
0

Summary: Learn how to use Windows PowerShell to show the status of optional features in AD DS.

Hey, Scripting Guy! Question How can I use Windows PowerShell and the Active Directory module to determine the status of optional features in AD DS?

Hey, Scripting Guy! Answer Use the Get-ADOptionalFeature Windows PowerShell cmdlet. You can use a wildcard for the filter to simplify returning results.

Get-ADOptionalFeature -Filter *

 


Explore Active Directory Users with PowerShell Out-GridView

0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using the Windows PowerShell Out-Gridview cmdlet to examine user information in Active Directory.

 

Hey, Scripting Guy! Question Hey, Scripting Guy! I would like a way to use Windows PowerShell to view user information from Active Directory. I would like to be able to explore the returned information and be able to see what is going on. In other words, I need kind of an Active Directory microscope. You don’t happen to have one do you?

—BJ

Hey, Scripting Guy! Answer Hello BJ,

Microsoft Scripting Guy, Ed Wilson, is here. This has been a really busy week, and it is now 30 days until the Windows PowerShell Summit in in Redmond, Washington. The Scripting Wife and I are looking forward to attending this event. In fact, we have been looking forward to it for months. Finally, it is coming together. In one way, it will be a bit strange. This is because we are staying at the same hotel as a couple of members from the Charlotte, North Carolina Windows PowerShell User Group, so I know we will be hanging out some. But of course, the big reason for attending the event is to spend time with some of the world’s best Windows PowerShell scripters. It will be a total geek fest the entire time. I will be making three presentations, and so next week I need to spend a decent amount of time honing them.

Note   This is the fifth blog in a series about using the Active Directory module.

Using Out-GridView to explore Active Directory user info 

One of the cool things I like to do with Windows PowerShell is pipe user information that I need to peruse to the Out-GridView cmdlet. I find it a very convenient way to explore user information. The result of this exploration can be a further refinement of an AD DS query, or it can be the end game itself. The command is simplicity itself. In the command that follows, I am on the Charlotte OU portion of my AD: drive. I use the diralias (alias for Get-ChildItem), and I specify that I want all properties by using a wildcard character. I pipe the results to Out-Gridview. That is it! 

PS AD:\ou=charlotte,dc=iammred,dc=net> dir -Properties * | Out-GridView

Sorting and filtering data with Out-GridView 

The initial display of information is not all that great. In fact, it seems a bit cluttered, and even jumbled. This is shown in the image that follows. 

Image of command output

The strength of using Out-GridView comes by adding a criteria. This is shown here.

Image of menu

After I select the attributes that I am interested in working with, I click Add. Now, the GridView changes to permit modifying the operator and adding the criteria. This is shown here.

Image of menu 

Storing results and further parsing

In Windows PowerShell 3.0, Out-GridView picks up a PassThruparameter. This means that the filtering conducted in the Out-GridView can feed back to the Windows PowerShell console. In the following example, I throw all the user objects (and their associated properties) from the Charlotte OU to the Out-GridView. I then filter the results and I store the results in a variable. Next I use Windows PowerShell to further work with the results. The command is shown here:

PS AD:\ou=charlotte,dc=iammred,dc=net> $user = dir -Properties * | Out-GridView –PassThru 

The Out-GridView that is created by the command is shown here. 

Image of menu

Note  If you do not highlight all the lines, only the one line that is highlighted by default returns. So in the previous image, the filter criterion returns three objects. But right now, only the first line is highlighted, so only that object would return. Therefore, all three lines need to be highlighted, and then when OK is pressed, all three objects return to the variable.

After filtering the objects with more than 500 logons, I go back to the Windows PowerShell console, and investigate the $user variable that contains the returned objects.

PS AD:\ou=charlotte,dc=iammred,dc=net> $user = dir -Properties * | out-gridview -Pass 

Thru 

PS AD:\ou=charlotte,dc=iammred,dc=net> $user.Count 

I do not even need to use an intermediate variable because I can pipe the results to another cmdlet. The following command pipes the results from whatever is filtered in the Out-Gridview cmdlet to Group-Object, where the objects are grouped by the name property.

PS AD:\ou=charlotte,dc=iammred,dc=net> dir -Properties * | out-gridview -PassThru | group name  

Count Name                      Group 

----- ----                      -----

    1 ED-PC                     {CN=ED-PC,OU=Charlotte,DC=iammred,DC=net}

    1 ed wilson                 {CN=ed wilson,OU=Charlotte,DC=iammred,DC=net}

    1 EDLT                      {CN=EDLT,OU=Charlotte,DC=iammred,DC=net}

    1 HYPERV2                   {CN=HYPERV2,OU=Charlotte,DC=iammred,DC=net}

    1 Regular User              {CN=Regular User,OU=Charlotte,DC=iammred,DC=net}

    1 Sample User               {CN=Sample User,OU=Charlotte,DC=iammred,DC=net}

    1 SQL                       {CN=SQL,OU=Charlotte,DC=iammred,DC=net

    1 Teresa Wilson             {CN=Teresa Wilson,OU=Charlotte,DC=iammred,DC=net}

BJ, that is all there is to using the Active Directory module provider with the Out-GridView cmdlet. Active Directory Week will continue tomorrow when I will talk about discovering attribute names by using Windows PowerShell.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Use PowerShell to Find Name & OS Version of Domain Controllers

0
0

Summary: Use Windows PowerShell to find the name and operating system version of all your domain controllers.

Hey, Scripting Guy! Question How can I use Windows PowerShell to find the name and operating system version of all my domain controllers?

Hey, Scripting Guy! Answer Use the Get-ADDomainController cmdlet from the Active Directory module and a wild card filter to select all domain controllers. Then pipe the results to the Select-Object cmdlet and choose the Name and OperatingSystem properties.

Get-ADDomainController -Filter * | select name, operatingsystem

Weekend Scripter: Explore AD DS Attributes with PowerShell

0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to discover the names of attributes in Active Directory Domain Services.

Microsoft Scripting Guy, Ed Wilson, is here. One of the great things about writing a blog is the comments I receive. Most of the time the comments add illuminating information, express thanks for a topic, or offer thoughts to contemplate further exploration. Today’s blog is a result of one of those comments. Thomas Brevig offered a way to find the name of an attribute in Active Directory Domain Services (AD DS) if he knew the value of the attribute. I thought the technique was great, and it showed that by piping Windows PowerShell pieces together, powerful solutions are easily built.

But I decided to see if I could find a different way to perform the search. The trick is that I access the underlying PSObject. So, the first thing I do is grab a user object with which I am interested in working. For this, I use the Get-ADUser cmdlet from the Active Directory module, and I choose all of the properties from the object. This command is shown here.

$user = get-aduser -filter "name -eq 'ed wilson'" -Properties *

If I use the Get-Member cmdlet to look at the user object stored in the $user variable the PSObjectproperty does not appear. To see this, I must add the Forceparameter to the Get-Member command. This technique is shown here.

$user | gm –Force

The command and its associated output are shown in the image that follows.

Image of command output

Now, I access the PSObjectproperty directly from the user object as shown here.

PS C:\> $user.psobject

 

Members             : {AccountExpirationDate, accountExpires, AccountLockoutTime,

                      AccountNotDelegated...}

Properties          : {AccountExpirationDate, accountExpires, AccountLockoutTime,

                      AccountNotDelegated...}

Methods             : {string get_GivenName(), void set_GivenName(string value),

                      string get_Surname(), void set_Surname(string value)...}

ImmediateBaseObject : CN=ed wilson,OU=Charlotte,DC=iammred,DC=net

BaseObject          : CN=ed wilson,OU=Charlotte,DC=iammred,DC=net

TypeNames           : {Microsoft.ActiveDirectory.Management.ADUser,

                      Microsoft.ActiveDirectory.Management.ADAccount,

                      Microsoft.ActiveDirectory.Management.ADPrincipal,

                      Microsoft.ActiveDirectory.Management.ADObject...}

I access the Properties of the PSObjectdirectly, and I get back a bunch of information about each of the properties stored in the collection. The command is shown here.

$user.psobject.Properties

The command and its associated output are shown in the following image.

Image of command output

This lets me know that the attribute name appears in the Nameproperty and the value in the Valueproperty. By using this information, I come up with the following command.

PS C:\> $user.psobject.Properties | ? value -match 'charlotte' | select name, value

 

Name                                       Value

----                                       -----

CanonicalName                              iammred.net/Charlotte/ed wilson

City                                       Charlotte

DistinguishedName                          CN=ed wilson,OU=Charlotte,DC=iammred,D...

l                                          Charlotte

Office                                     Charlotte office

physicalDeliveryOfficeName                 Charlotte office

If I am doing this in Windows PowerShell 2.0, I would not use the simplified Where-Object syntax. Instead, the command would appear as:

$user.psobject.Properties | ? {$_.value -match 'charlotte'} | select name, value

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

PowerTip: Use PowerShell to Find Domain Naming Context

0
0

Summary: Learn how to use Windows PowerShell to easily find the naming contexts for your AD DS domain.

 

Hey, Scripting Guy! Question How can I use a Windows PowerShell cmdlet to find information about my naming contexts for Active Directory Domain Services (AD DS)? 

Hey, Scripting Guy! AnswerUse Get-ADRootDSE from the Active Directory module, pipe the results to the Select-Object cmdlet, and use a wildcard pattern to select *naming*. 

Get-ADRootDSE | select *naming* 

Weekend Scripter: Convert Word Documents to PDF Files with PowerShell

0
0

Summary: Windows PowerShell MVP, Sean Kearney, talks about using Windows PowerShell to convert Word documents to PDF files en-masse.

Microsoft Scripting Guy, Ed Wilson, is here. Today’s blog is brought to you by Windows PowerShell MVP and honorary Scripting Guy, Sean Kearney.

Previous blog posts by Sean Kearney

Take it away Sean…

My boss looks up at me today, and sighs, “I love the built-in SaveAs PDF in Word 2013. But I want to do multiple documents at the same time. Oh, if ONLY there was some way to do this in bulk.”

The wires and lights starting blinking in my head. I’m about to leap out of my chair because I hear “Bulk.” Many to do, repeatable, and…

POWERSHELL!

So accessing a file in Microsoft Word programmatically is quite easy. We’ve been doing it for years.

$Word=NEW-OBJECT –COMOBJECT WORD.APPLICATION

$Doc=$Word.Documents.Open(“C:\Foofile.docx”)

And along the same lines, we could save this same file in the following manner.

$Doc.saveas([ref] “C:\Foofile.docx”)

If we would like to save it in an alternate format, like in .pdf format, things get a wee bit fancier. We have to speak a bit of .NET.

$Doc.saveas([ref] “C:\Foofile.pdf”, [ref] 17)

If your brain didn’t pop out just now, you’re OK. Let’s get a little fancier. What if I want Microsoft Word to save that PDF file with the same name as the parent without knowing the name?

Now we’re stepping into the land of fun. We can access the file name of that single document in the following way. Three of the available properties in the Word object are the Name of the document, the Path to the document, and the FullName path. I poked out using the following cmdlet to…well, to be honest…to guess.

$Doc | get-member –membertype property *Name*

Image of command output

Note the two little nuggets. In poking about and using a similar search for Path,  I found the property holding its path.

$Doc | get-member –membertype property *Path*

So I could do something like this: Open some file, get the file name information, swap out .docx with .pdf, and then save it.

Image of command output

With these three bits of information, I don’t have to actually know  the file name. Word will tell me based on the document. But let’s simplify this down a bit. Let’s just take a known file name and resave it as a PDF file with the same file name. All we need to do is run a Replace() method on the provided file name, and swap .docx with .pdf.

Yes….we’re presuming it’s a .pdf, J.

$File=”C:\Foofolder\foofile.docx”

$Word=NEW-OBJECT –COMOBJECT WORD.APPLICATION

$Doc=$Word.Documents.Open($File)

$Doc.saveas([ref] (($File).replace(“docx”,”pdf”)), [ref] 17)

$Doc.close()

So that’s all fine and dandy. But what if we have a folder of DOCX files that we want to convert at once?

Let’s pretend we ran the following lines in Windows PowerShell:

$File=”C:\Foofolder\foofile.docx”

$Files=GET-CHLDITEM ‘C:\FooFolder\*.DOCX’

Now we could cheat and access the full file name and path by accessing the FullName from the drive system. But let’s have some fun with Word and ask it these questions.

Foreach ($File in $Files) {

    # open a Word document, filename from the directory

    $Doc=$Word.Documents.Open($File.fullname)

Now let’s ask Word what is the name of the file. And while we’re at it, let’s swap the .docx file extension with .pdf.

  $Name=($Doc.Fullname).replace(“docx”,”pdf”)

Then we’ll access that file within Microsoft Word and use the built-in SaveAs PDF option in Word 2010 or Word 2013 to produce a PDF file in the same folder as the original Word document. When done, we close the file.

    $Doc.saveas([ref] $Name, [ref] 17)

    $Doc.close()

}

So when done our script will look like this:

# Acquire a list of DOCX files in a folder

$Files=GET-CHLDITEM ‘C:\FooFolder\*.DOCX’

 

Foreach ($File in $Files) {

    # open a Word document, filename from the directory

    $Doc=$Word.Documents.Open($File.fullname)

 

    # Swap out DOCX with PDF in the Filename

$Name=($Doc.Fullname).replace(“docx”,”pdf”)

 

    # Save this File as a PDF in Word 2010/2013

    $Doc.saveas([ref] $Name, [ref] 17)

    $Doc.close()

}

So why the big secrecy about using the document names in Word itself? In the future, I’ll show you how to programmatically trigger a mail merge, and you’ll see where it’s needed there.

Cheers and remember to keep on scriptin’.

~Sean,
The Energized Tech

Thanks, Sean, for taking the time to share your scripting expertise with us today. Join me tomorrow when I have a guest blog post from Ingo Karstein about using Windows PowerShell with SharePoint. It is cool and you do not want to miss it.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Use PowerShell to Find Your Word Version

0
0

Summary: Use Windows PowerShell to identify the version of Microsoft Word you are running.

Hey, Scripting Guy! Question How can I use Windows PowerShell to find the version of Microsoft Word that is installed on my system?

Hey, Scripting Guy! Answer Create an instance of the Word.Application object, and then choose the Version property:

PS C:\> (New-Object -ComObject word.application).version

15.0

 

Learn About Using PowerShell Value Binding by Property Name

0
0

Summary:  Guest blogger, Ingo Karstein, talks about using Windows PowerShell and value binding by property name.

Microsoft Scripting Guy, Ed Wilson, is here. Today our blog is written by Ingo Karstein who has shared his knowledge previously with us. Ingo is an independent consultant for SharePoint and Windows PowerShell based in Leipzig, Germany and a Microsoft Certified Master for SharePoint 2010.

Take it away, Ingo…

Do you know about value binding by property name in Windows PowerShell pipelines and what it is good for? I’d like to explain it to you!

First, what is value binding? In a Windows PowerShell pipeline context, it is possible to transfer (pipe) objects from one cmdlet to another.

Here is a simple example:

You can use Get-ProcessIExplore to retrieve all Internet Explorer processes as .NET objects. With the cmdlet Stop-Process, you can stop processes. A WindowsPowerShell pipeline connects both cmdlets. By piping the Internet Explorer objects from Get-Process to Stop-Process, you can stop the processes.

Get-Process "IExplore" | Stop-Process

Image of command output

When you use this command, you are using a Windows PowerShell pipeline marked by the pipe character ( | ), and you use value binding. The Stop-Process cmdlet has a parameter called InputObject, which accepts process objects to do its work. You could also use a variable to specify the InputObject parameter.

Image of command output

The example in the previous screenshot shows an explicit value binding of the $ie variable to the InputObject parameter. The Windows PowerShell pipeline does exactly the same, but implicitly! It takes one or more objects from Get-Process and tries to bind them to some parameter of the Stop-Process cmdlet. “Some parameter” means that Windows PowerShell analyzes the cmdlet and its parameters, and if a parameter’s data type matches the given object’s data type, it binds the object to the parameter and runs the command.

The following image shows a look into the Windows PowerShell internal Help for Stop-Process.

Image of command output

You can see that the InputObject parameter accepts an array (marked by “[ ]”) of Process objects through the pipeline by using ByValue.

Now let’s get closer to the main topic of this blog post: Value binding by property name.

Let’s have a look at another parameter of Get-Process called Name.

Image of command output

Like the InputObject parameter, Name also accepts pipeline input, but by using ByPropertyName instead of ByValue as in the previous screenshot.

Now let’s try to run the command first with an explicit data-type string value for the Name parameter. This works as expected.

Image of command output

Now we try to bind the string value IExplore to the parameter by using a Windows PowerShell pipeline.

Image of error message

This presents an error message because there is no parameter for the Stop-Process cmdlet that accepts string (or array of strings) data as ByValue pipeline input.

So how can we use the pipeline binding for the Name parameter that is marked with ByPropertyName? Let’s say we have a certain object that has a property called Name like the following object:

Image of command output

The object in the $myObject variable has only one property (Name) with the IExplore value.

Now we can use this object as pipeline input.

Image of command output

No error message here! The pipeline engine of Windows PowerShell does a lot of simple magic here. It tries to match all properties of the input object to the cmdlet. This match is done by name. The input object in the example has a Name property of the type String, and the Stop-Process cmdlet has a Name parameter that accepts String values. This is a perfect match!

The match also works if the input object has more properties.

Image of command output

When you run $myObject | Stop-Process again, it will also match the Name property and the Name parameter. But it does not work for an object that has no Name property.

Image of error message

Here is how I created the object in the $myObject variable:

Image of command output

I created a new empty Windows PowerShell object by using New-Object System.Management.Automation.Object, and I added some properties by using the Add-Member cmdlet. This is a very cool feature in Windows PowerShell that allows you to create custom objects on the fly and work with them.

Now a more complex example…

Let’s say you want to import some plain text log files into Windows PowerShell. For each log file, you want to specify the file name plus the number of lines you want to read from the beginning of the file or the number of lines to read from the end of the file. You could use the following.

Image of command output

Following is the Help information about Get-Content.

Image of command output

As you can see, three parameters can be bound by Property name. If you have a certain objects with corresponding Property names, you can pass these objects to the cmdlet and bind the parameters to the object values.

Let’s create some objects:

$log1 = New-Object System.Management.Automation.PSObject

$log1 | Add-Member -Name "Path" -Value "Log1.txt" -MemberType NoteProperty

$log1 | Add-Member -Name "TotalCount" -Value 3 -MemberType NoteProperty

 

$log2 = New-Object System.Management.Automation.PSObject

$log2 | Add-Member -Name "Path" -Value "Log2.txt" -MemberType NoteProperty

$log2 | Add-Member -Name "TotalCount" -Value 5 -MemberType NoteProperty

 

$log3 = New-Object System.Management.Automation.PSObject

$log3 | Add-Member -Name "Path" -Value "Log3.txt" -MemberType NoteProperty

$log3 | Add-Member -Name "Tail" -Value 2 -MemberType NoteProperty

 

$log4 = New-Object System.Management.Automation.PSObject

$log4 | Add-Member -Name "Path" -Value "Log4.txt" -MemberType NoteProperty

$log4 | Add-Member -Name "Tail" -Value 4 -MemberType NoteProperty

This is how they look:

Image of command output

Now you can use them together as pipeline input. The pipeline engine will always match the corresponding properties and parameters by their names.

Image of command output

The command @($log1, $log2, $log3, $log4) | Foreach-Object { $_ | Get-Content } looks strange, doesn’t it? If you try to run @($log1, $log2, $log3, $log4) | Get-Content, you will see that it fails for the objects in variables $log3 and $log4 because Get-Content does not allow the TotalCount and Tail parameters side-by-side.

You might say $log3 and $log4 do not have a TotalCount property. You are correct! But through the first two objects, $log1 and $log2, the pipeline engine expects that all pipeline input objects will have at least two properties: Path and TotalCount. For $log3 and $log4, it finds one additional input parameter, called Tail, which theoretically can be bound by property name.

It tries to bind the already known TotalCount property with a value of $null, and the new Tail property with a real value at the same time. That fails because Tail and TotalCount cannot coexist in one call. In the previous screenshot, all objects are piped to the Get-Content cmdlet separately.

One step further…

I am writing this blog because I used value binding by property name in a Windows PowerShell project about importing and exporting design packages. For more information, see:

In those scripts, I wanted to call Windows PowerShell Cmdlet Binding-enabled functions by using hash tables. I wanted to bind named hash table items to cmdlet parameter names. The following example shows an array of four hash tables.

@(

    @{ Path="Log1.txt"; TotalCount=3 },

    @{ Path="Log2.txt"; TotalCount=5 },

    @{ Path="Log3.txt"; Tail=4 },

    @{ Path="Log4.txt"; Tail=2 }

)

I want to use them as pipeline input for the Get-Content cmdlet, but as you can see, it does not work. There is no cmdlet parameter for Get-Content that accepts a hash table as input.

Image of error message

Therefore, I created a function that enables this scenario by creating objects out of hash tables. Here I use the Add-Member cmdlet as shown earlier.

function New-ObjectFromHashtable {

            [CmdletBinding()]

            param(

                        [parameter(Mandatory=$true, Position=1, ValueFromPipeline=$true)]

                        [Hashtable]

                        $Hashtable

            )

 

            begin { }

 

            process {

                        $r = new-object System.Management.Automation.PSObject

           

                        $Hashtable.Keys | % {

            $key=$_

                                    $value=$Hashtable[$key]

 

                                    $r | Add-Member -MemberType NoteProperty -Name $key -Value $value -Force

                        }

 

                        $r

            }

 

            end { }

}

This takes hash tables as pipeline input. For each hash table in the pipeline, the function creates a new object. For each key in the hash table, the function adds a property to the object and sets the value of the property to the value of the hash table item referenced by the key. The result is a list of objects. The function itself can be used in a pipeline.

Image of command output

I hope you will find this function useful in your own scripts when you want to utilize pipeline binding by property name to set multiple cmdlet parameter values at once.

Thanks for reading!

~Ingo

Thank you Ingo! This excellent blog should prove to be immediately valuable to many of the readers. Join me tomorrow when I will talk about more cool stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 


PowerTip: Display Hidden Files by Using PowerShell

0
0

Summary: Learn how to display hidden files by using Windows PowerShell.

Hey, Scripting Guy! Question How can I use Windows PowerShell to display hidden files?

Hey, Scripting Guy! Answer Use the Force parameter for Get-Childitem (or the aliases dirls or gci):

dir -Force -File

Decrypt PowerShell Secure String Password

0
0

Summary: Microsoft Scripting Guy, Ed Wilson, shows how to easily decrypt the Windows PowerShell secure string password.

Hey, Scripting Guy! Question Hey, Scripting Guy! We have an FTP site that I have to use on a regular basis. I need an easy way to get a credential and use that credential with the FTP site so that I can download a file that changes on a daily basis. I found a few scripts and functions on the Internet that will decrypt the secure string password from a Windows PowerShell credential object, but they all seem really complicated. Is there an easy way to do this?

—AD

Hey, Scripting Guy! Answer Hello AD,

Microsoft Scripting Guy, Ed Wilson, is here. Today I am sitting here drinking a cup of Earl Grey tea with a pinch of lavender in it. I love the way the two flavors complement each other. As I look over my email, I ran across your question. Although you did not include a link to the complicated versionsof the scripts and functions you ran across, I will venture to say that my method should be relatively painless.

           Note  What I am showing here today is exactly by design, and is not a hack.

Using Get-Credential for credentials

I love using the Get-Credential cmdlet to retrieve a credential object. It is already set up to work; and therefore, it is easy to use. If I need credentials, I do not need to mess around writing HTAs, creating various WinForms to prompt for a user name and password, or worry about how to mask the password—all of which were problems before Windows PowerShell and the Get-Credential cmdlet. So, like I say, I absolutely love it. To use the Get-Credential cmdlet, I generally store the resulting credential object in a variable. (I do not have to do so, because I can use it directly if I need to, but it is more flexible to store it in a variable.) Here is the command.

$credential = Get-Credential

When I run this command, a dialog box appears. The box is already set up to use, with a user name on the top, and it masks the password in the bottom box. The box is shown here.

Image of dialog box

 The problem with Get-Credential

The problem with the Get-Credential cmdlet is that it returns a PSCredential object. In itself, this is not an issue, but it does mean that I can only use the credential object for cmdlets and for other items that know what a PSCredential object is. Not even all .NET classes know how to deal with a PSCredential object, so when it comes to connecting to legacy databases and things like websites and FTP sites, there is little hope of being able to use the object directly.

Luckily, I can use the Get-Member cmdlet to look at the members of a PSCredential object. The members are listed here.

PS C:\> $credential | gm 

   TypeName: System.Management.Automation.PSCredential

 

Name                 MemberType Definition

----                 ---------- ----------

Equals               Method     bool Equals(System.Object obj)

GetHashCode          Method     int GetHashCode()

GetNetworkCredential Method     System.Net.NetworkCredential GetNetworkCredential()

GetObjectData        Method     void GetObjectData(System.Runtime.Serialization.S...

GetType              Method     type GetType()

ToString             Method     string ToString()

Password             Property   securestring Password {get;}

UserName             Property   string UserName {get;}

At first, it looks like things are relatively easy. If I want to see the user name, all I need to do is access the UserNameproperty as shown here.

PS C:\> $credential.UserName

mydomain\someuser

That is cool. Now what about the password? When I access the Passwordproperty, it returns SecureString. This is shown here.

PS C:\> $credential.Password

System.Security.SecureString

Hmmm, what if I look at the members of SecureString? I pipe it to the Get-Member cmdlet, and I see the following members.

PS C:\> $credential.Password | gm 

   TypeName: System.Security.SecureString

 

Name         MemberType Definition

----         ---------- ----------

AppendChar   Method     void AppendChar(char c)

Clear        Method     void Clear()

Copy         Method     securestring Copy()

Dispose      Method     void Dispose(), void IDisposable.Dispose()

Equals       Method     bool Equals(System.Object obj)

GetHashCode  Method     int GetHashCode()

GetType      Method     type GetType()

InsertAt     Method     void InsertAt(int index, char c)

IsReadOnly   Method     bool IsReadOnly()

MakeReadOnly Method     void MakeReadOnly()

RemoveAt     Method     void RemoveAt(int index)

SetAt        Method     void SetAt(int index, char c)

ToString     Method     string ToString()

Length       Property   int Length {get;}

Ok, cool. I will try the ToStringmethod and see what happens.

PS C:\> $credential.Password.ToString()

System.Security.SecureString

Well, that was less than illuminating…

What if I try the Lengthproperty? Does it give me anything?

PS C:\> $credential.Password.Length

17

It does.This is promising. I can at least write code that checks the length of the password and provides some sort of feedback to users regarding the length of the password they supply. It could be rather a cool solution.

What if I use the ConvertFrom-SecureString cmdlet? This is a standard Windows PowerShell cmdlet, so I decide to pipe the password to the ConvertFrom-SecureString cmdlet. The following illustrates the output.

PS C:\> $credential.Password | ConvertFrom-SecureString

01000000d08c9ddf0115d1118c7a00c04fc297eb0100000052ded6c2db80e748933432e19b9de8b10000

000002000000000003660000c00000001000000016dc35885d76d07bab289eb9927cfc1e000000000480

0000a0000000100000003106cde553f45b08d13d89d11336170b280000005cc865c1ee1b57e84ed3d1a2

d3f2d0ec0f189b532e61c18d1f31444d6f119a1e8368477fd2d81f54140000000cb0262e58b08ae14f37

22c14c69684841b6b21c

This latest representation is a string, and therefore there are no more options available for decrypting the password—at  least, none that are very direct or easy to use.

Get a network credential

The solution, is to go back to the PSCredential object itself. It has a method that is designed to help with the exact scenario. I need to provide credentials to a legacy type of interface that does not know how to handle a PSCredential. Therefore, I need to be able to get both the user name and the password in an easy-to-use and easy-to-digest manner. When I call the GetNetworkCredential method from the PSCredential object, it returns the user name and the domain name. This is shown here.

PS C:\> $credential.GetNetworkCredential() 

UserName                                           Domain

--------                                           ------

someuser                                           mydomain

If I pipe the returned object to the Get-Member cmdlet, however, I see that I now have a NetworkCredential object. The members are listed here.

PS C:\> $credential.GetNetworkCredential() | gm 

   TypeName: System.Net.NetworkCredential

 

Name           MemberType Definition

----           ---------- ----------

Equals         Method     bool Equals(System.Object obj)

GetCredential  Method     System.Net.NetworkCredential GetCredential(uri uri, str...

GetHashCode    Method     int GetHashCode()

GetType        Method     type GetType()

ToString       Method     string ToString()

Domain         Property   string Domain {get;set;}

Password       Property   string Password {get;set;}

SecurePassword Property   securestring SecurePassword {get;set;}

UserName       Property   string UserName {get;set;}

I see the password has a SecureString for the SecurePassword property, but there is also the Password property that is a plain string. So, I pipe the NetworkCredential object to the Format-List cmdlet and the following appears.

PS C:\> $credential.GetNetworkCredential() | fl * 

UserName       : someuser

Password       : SomeUsersPassword

SecurePassword : System.Security.SecureString

Domain         : mydomain

If I need only the password, I simply retrieve the Passwordproperty as shown here.

PS C:\> $credential.GetNetworkCredential().password

SomeUsersPassword

By the way, I can also get the password length here. This is because all string objects contain a Length property. This is shown here.

PS C:\> $credential.GetNetworkCredential().password.length

17

AD, that is all there is to using the NetworkCredential object. Join me tomorrow when I will talk about more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

PowerTip: Store PowerShell Credentials

0
0

 

Summary: Store your Windows PowerShell credentials in a variable for later use.

Hey, Scripting Guy! Question How can I store alternate credentials for repeated use in my Windows PowerShell session?

Hey, Scripting Guy! AnswerUse the Get-Credential cmdlet to prompt for a credential, and store the results in a variable:

$credential = Get-Credential

 

Troubleshoot the InvokeMethodOnNull Error with PowerShell

0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about troubleshooting the InvokeMethodOnNull error in a Windows PowerShell script.

Hey, Scripting Guy! Question Hey, Scripting Guy! Ed...thank you for all you do for those of us who are spread so thin we can't go deep on subjects like scripting. I have a question regarding a script you created in Use PowerShell to Create an HTML Uptime Report, called HTML_UptimeReport.ps1. I have downloaded the file, put my own list of hosts in, and it works, but there are errors regarding the $os.converttodatetime expression.

When I run the script I get an error message about not calling a method on a null-valued expression. Here is the actual error message:

You cannot call a method on a null-valued expression. At H:\My Files\Scripts\AD Scripts\Get-Uptime-Script.ps1:20 char:51 + uptime = (get-date) - $os.converttodatetime <<<< ($os.lastbootuptime)}}} + CategoryInfo : InvalidOperation: (converttodatetime:String) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull

If you have a few minutes, would you mind helping me understand the reason for the error? Thank you again.

—DJ

Hey, Scripting Guy! Answer Hello DJ,

Microsoft Scripting Guy, Ed Wilson, is here. When you get an error such as “you cannot call an expression on a null value,” it means the script is attempting to do something, but another part of the script does not have any information to permit the first part of the script to work properly.

In a script that previously worked, this error is almost always a symptom of an earlier failure. What that earlier failure is could be something like permissions or configuration. In a script that is currently under development or being modified from a previously working script, this error usually arises from a problem with code that either returns information in an unexpected format or does not return any information at all.

To troubleshoot this issue in your script, you need to examine the code that populates the $os variable. Because I am calling the ConvertToDateTime method from the WMI object stored in the $os variable it means there must be a valid WMI object in the variable, or else we cannot call the method.

Upon closer examination, your error message tells me that $os does not contain a value for the LastBootUpTime property. The LastBootUpTime property is probably empty; and therefore, when the script attempts to call the ConvertToDateTime, method there is nothing there. Thus the error tells you that you cannot call an expression on a null value. It actually makes sense—there is nothing that can be converted to a DateTime object.

Your task is to find out why you are not getting a value for the LastBootUpTime property. I would troubleshoot this by using Get-WMIobject directly on the WMI class (I think it is WIN32_operating system, but as you said, I wrote this in August and I am writing this from memory) by making the query and seeking for a value in the LastBootUpTime property. You can do this simple enough by formatting as a list and using a *. The command would look like this (using aliases and querying the local computer):

gwmi win32_operatingsystem | fl *

DJ, that is all there is to troubleshooting the error message you are receiving. Join me tomorrow when I will have a guest blog by Microsoft PowerShell MVP, Jeff Wouters, as he talks about preparing for the 2013 Scripting Games.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

PowerTip: Get the Last Boot Time with PowerShell

0
0

Summary: Learn how to get the last boot time for your computer.

Hey, Scripting Guy! Question How can I find the last boot time for my computer by using Windows PowerShell?

Hey, Scripting Guy! Answer In Windows PowerShell 3.0, use the Get-CimInstance cmdlet, and select the LastBootUptime property from the Win32_Operatingsystem WMI class:

PS C:\> Get-CimInstance -ClassName win32_operatingsystem | select csname, lastbootuptime

csname                                     lastbootuptime

------                                     --------------

EDLT                                       3/22/2013 11:27:01 AM

Hey, Scripting Guy! Answer In Windows PowerShell 2.0 and Windows PowerShell 1.0, use the Get-WmiObject cmdlet, and then translate the returned date to a readable format:

PS C:\> Get-WmiObject win32_operatingsystem | select csname, @{LABEL='LastBootUpTime'

;EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}}

csname                                     LastBootUpTime

------                                     --------------

EDLT                                       3/22/2013 11:27:01 AM

 

 

Viewing all 3333 articles
Browse latest View live




Latest Images