Quantcast
Channel: Scripting Blog
Viewing all 2129 articles
Browse latest View live

PowerTip: Examine the Most Recent PowerShell Error

$
0
0

Summary: Learn how to examine the most recent error in Windows PowerShell.

Hey, Scripting Guy! Question My Windows PowerShell command failed with an error. How can I look at the error record?

Hey, Scripting Guy! Answer Use the $error automatic variable to it displays the last error.
          You can see more details by piping it to the Format-List cmdlet and using –Force:

$error | Format-List * -Force


Weekend Scripter: From Zero to PowerShell Hero

$
0
0

Summary: Microsoft MVP and winner of the Scripting Games, Taylor Gibb, talks about his experience with Windows PowerShell and IT in general.

Microsoft Scripting Guy, Ed Wilson, is here. One of the great things about TechEd is getting to talk to the various people that I meet virtually. One person who was both fun and inspirational to talk to was Taylor Gibb, who is the winner of this year's Scripting Games. I asked Taylor if he would be willing to share his story. So today we have a new guest blogger, Taylor Gibb. I will let Taylor tell you about himself...

I was born and raised in Durban, South Africa. I am a software developer and the youngest Microsoft MVP in the world. Last year, in 2013, I won the Windows PowerShell Scripting Games and this is my story.

It all started about five years ago. I was 15 years old at the time, and I had made the decision to leave school. Most people would call this a mistake; but in reality, it turned out to be the best decision I would ever make. You see, deep inside I had this extreme curiosity about computers, and the education system I was a part of was simply not satisfying this curiosity. Months went by as I sat at home in my bedroom teaching myself about what makes computers tick.

But as we all know, there is only so much a 15-year old can learn on his own.

One day my mom came home with a pamphlet for a private college offering a range of Microsoft courses based on what was then the MCSE curriculum. My eyes immediately lit up! The course was not cheap, but nevertheless, we went for an interview at what is now iStudent. After explaining the situation, I was granted the last seat.

Fast forward my life a year or so, and this is pretty much where my career in IT started. The college where I wrote my exams was looking for more staff, and they offered me a position teaching the Microsoft curriculum I had studied, if I attained my Microsoft Certified Trainer (MCT) qualification. Obviously, I couldn’t pass up this opportunity. While working there, many of the courses I had studied were revised. This was my first encounter with Windows PowerShell.

From iSolve, I was hunted down by the recruiters at Derivco who used to send their staff for training regularly. My first job at Derivco was on the Environments team. Here, a small team used all sorts of magic to maintain the development and test environments. One strength I brought to the table was my ruthless ability to automate anything and everything, and my tool of choice had become Windows PowerShell. I ended up getting to do loads of cool stuff with Windows PowerShell during my time on this team. It’s also pretty much when my love for the language started.

In June 2013, shortly after I had received my first Microsoft MVP award, I decided to learn as much as I could about Windows PowerShell. The first step in this long journey would be entering the Scripting Games. Learning from my mistakes and taking notes as I went along, I entered the competition one challenge at a time. To make the story slightly shorter, I ended up winning, and the Windows PowerShell team at Microsoft invited me to a team dinner at either TechEd Europe or the TechEd North America.

I was already attending TechEd North America due to speaking engagements, so I took it as the perfect opportunity to catch up with the guys. I arrived at the House of Blues slightly early, not realizing it was just down the road from my hotel. To my surprise, there were already some familiar faces around. Jason Helmick, Don Jones, Mike Robbins, and I had a drink while we waited for the rest of the team to arrive.

As you can imagine, Windows PowerShell was pretty much the only thing we discussed during this time. Jeffery Snover (the father of the Shell) arrived after everyone had been seated, and to my surprise, he took a seat right next to me.

These days I am a full-time software developer on the Mobile Services team at Derivco. Recently, I have been writing a system that allows us to send push notifications to all of our mobile apps. In my spare time, I travel the world speaking to pretty much anyone and everyone who will listen to me talk about .NET-based software development.

If you can't find me speaking at an event in your area, you can follow me on Twitter (@taybgibb) or subscribe to my newly revamped blog (www.taylorgibb.com) to hear what I have to say about everything that is code related.

~Taylor

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: Find PowerShell Variables in Various Scopes

$
0
0

Summary: Learn how to find Windows PowerShell variables in various scopes.

Hey, Scripting Guy! Question How can I see what Windows PowerShell variables exist in various scopes?

Hey, Scripting Guy! Answer Use the Get-Variable cmdlet and use the –Scope modifier (this can be globallocal, or script), for example:

Get-Variable -Scope global

Piping Results from One PowerShell Cmdlet to Another

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about piping the results from one cmdlet to another.

Hey, Scripting Guy! Question Hey, Scripting Guy! I have a problem. When I pipe information from one Windows PowerShell cmdlet to anther (for example, when I use Get-Process and pipe it to Stop-Process ), sometimes it works, and sometimes it does not. This is not great. What is the deal? Can you help?

—LR

Hey, Scripting Guy! Answer Hello LR,

Microsoft Scripting Guy, Ed Wilson, is here. The nice thing about a hurricane is when it is gone. In Charlotte, we got some pretty heavy rain as a result of Hurricane Arthur, but nothing serious. Now we are enjoying the cool weather that followed that event. It seems like autumn outside.

LR, using the Windows PowerShell pipeline is not really like a hurricane, but sometimes it seems unpredictable. Therefore, things can appear to go around in circles. The key to knowing what is going on is understanding parameter sets.

For example, if I use Start-Process, I can easily start a new process. I can then use Get-Process to retrieve that process. This is shown here:

PS C:\> Start-Process notepad

PS C:\> get-Process notepad

 

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName

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

     84       8     1508       8112   110     0.08   5412 notepad

It would seem to make sense that I can now pipe the results to the Stop-Process cmdlet and stop the process. But if I do this, I get the following error message:

PS C:\> get-Process notepad | Stop-Process notepad

Stop-Process : Cannot bind parameter 'InputObject'. Cannot convert the "notepad" value

of type "System.String" to type "System.Diagnostics.Process".

At line:1 char:36

+ get-Process notepad | Stop-Process notepad

+                                    ~~~~~~~

    + CategoryInfo          : InvalidArgument: (:) [Stop-Process], ParameterBindingException

    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Comman

   ds.StopProcessCommand

The key is to realize this is not a “bogus error.” Rather, there is significant information here. It tells me that the cmdlet tries to bind the parameter InputObject, but that it does not work because “notepad” is a string and not a process object.

Three parameter sets

The Stop-Process cmdlet accepts the following three parameter sets:

PS C:\> Get-Command Stop-Process -Syntax

Stop-Process [-Id] <int[]> [-PassThru] [-Force] [-WhatIf] [-Confirm] [<CommonParameters>]

 

Stop-Process -Name <string[]> [-PassThru] [-Force] [-WhatIf] [-Confirm]

[<CommonParameters>]

 

Stop-Process [-InputObject] <Process[]> [-PassThru] [-Force] [-WhatIf] [-Confirm]

[<CommonParameters>]

The default parameter set is ID, which accepts an integer in the first position. To find this information about parameter sets, use the Get-Command cmdlet and pipe the output to Select-Object while expanding the ParameterSets parameter.

Here is a sample of the output for the first parameter (ID). The output shows that ID is the default parameter set, and that ID appears in the first position and is mandatory. It also tells us that this parameter does not accept a value from the pipeline.

PS C:\> Get-Command Stop-Process | select -expand parametersets

 

Parameter Set Name: Id

Is default parameter set: True

 

  Parameter Name: Id

    ParameterType = System.Int32[]

    Position = 0

    IsMandatory = True

    IsDynamic = False

    HelpMessage =

    ValueFromPipeline = False

    ValueFromPipelineByPropertyName = True

    ValueFromRemainingArguments = False

    Aliases = {}

    Attributes =

      System.Management.Automation.ParameterAttribute

What about the Name parameter? Well, there is a Name parameter set. It is not the default parameter set, and it also does not accept a value from the pipeline. This is shown here:

Parameter Set Name: Name

Is default parameter set: False

 

  Parameter Name: Name

    ParameterType = System.String[]

    Position = -2147483648

    IsMandatory = True

    IsDynamic = False

    HelpMessage =

    ValueFromPipeline = False

    ValueFromPipelineByPropertyName = True

    ValueFromRemainingArguments = False

    Aliases = {ProcessName}

    Attributes =

      System.Management.Automation.AliasAttribute

      System.Management.Automation.ParameterAttribute

So, when I try to tell the Stop-Process cmdlet that I want to stop the Notepad process, it does not work because it recognizes that “notepad” is not a number, so we are not using the default parameter set. Also it is not using the Name parameter set because it does not accept the pipelined input. So, how can it work?

That is easy! Remove the word Notepad, and it works just fine. I know this will work because of the third parameter set, which accepts pipelined input:

Parameter Set Name: InputObject

Is default parameter set: False

 

  Parameter Name: InputObject

    ParameterType = System.Diagnostics.Process[]

    Position = 0

    IsMandatory = True

    IsDynamic = False

    HelpMessage =

    ValueFromPipeline = True

    ValueFromPipelineByPropertyName = False

    ValueFromRemainingArguments = False

    Aliases = {}

    Attributes =

      System.Management.Automation.ParameterAttribute

So, all I need to do is to pipe a process object to the Stop-Process cmdlet, and it will stop that process. I can see what process it stops by using the –PassThru parameter, as shown here:

PS C:\> get-Process notepad | Stop-Process -PassThru

 

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName

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

     84       8     1488       8112    98     0.08   5412 notepad

LR, that is all there is to using the pipeline. Poshpourri Week will continue 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: Find Information About PowerShell Cmdlet Parameter Sets

$
0
0

Summary: Learn how to find information about Windows PowerShell cmdlet parameter sets.

Hey, Scripting Guy! Question How can I find information about the various parameter sets for a specific Windows PowerShell cmdlet?

Hey, Scripting Guy! Answer Use Get-Command to return cmdlet information, pipe the results to the Select-Object cmdlet,
          and expand the ParameterSets property:

Get-Command Stop-Process | select -expand parametersets

Getting to Know ForEach and ForEach-Object

$
0
0

Summary: Learn the differences between ForEach and ForEach-Object in Windows PowerShell.

Honorary Scripting Guy and Windows PowerShell MVP, Boe Prox, here today filling in for my good friend, The Scripting Guy. Today I am going to talk about some differences between using ForEach and using ForEach-Object in day-to-day scripting activities.

There are times when you are unable to make use of a cmdlet that has built-in pipeline support, such as something like this:

Get-ChildItem –File –Filter “*.TMP” | Remove-Item –Verbose

To get around this, we can make use of some other capabilities of Windows PowerShell by using ForEach or ForEach-Object to iterate through collections and to perform an action against each item in the collection. Each of these approaches can let you run through a collection and then perform actions in a script block. What you may not know is that each cmdlet has two approaches to how they take and handle the collections.

Let's take a look at ForEach-Object and see what it is about. This cmdlet has a couple of aliases that may seem familiar to you:

Get-Alias –Definition ForEach-Object

Image of command output

Wait a second! Why in the world are there two ForEach options in Windows PowerShell? This is an excellent question, and fortunately, I have an answer. When you are piping input into ForEach, it is the alias for ForEach-Object. But when you place ForEach at the beginning of the line, it is a Windows PowerShell statement.

ForEach-Object is best used when sending data through the pipeline because it will continue streaming the objects to the next command in the pipeline, for example:

ForEach-Object -InputObject (1..1E4) {

    $_

} | Measure-Object

 

Count    : 10000

Average  :

Sum      :

Maximum  :

Minimum  :

Property :

You cannot do the same thing with ForEach () {} because it will break the pipeline and throw error messages if you attempt to send that output to another command.

ForEach ($i in (1..1E4)) {

    $i

} | Measure-Object

 

At line:3 char:3

+ } | Measure-Object

+   ~

Note that an empty pipe element is not allowed.

    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException

    + FullyQualifiedErrorId : EmptyPipeElement

You would have to save all of the output that is being process by ForEach to a variable and then pipe it to another cmdlet, for example:

$Data = ForEach ($i in (1..1E4)) {

    $i

}

$Data | Measure-Object

The fact that now we have totally broken the pipeline becomes more apparent after this. Not only do we have to stop the pipeline to begin processing the data, we cannot even send that data to the pipeline from the statement without first collecting the output into a variable and then sending it down the pipeline.

This is very important if you plan to use the data in another command through the pipeline. It is important to note another difference that these options share, which is performance vs. memory consumption.

The ForEach statement loads all of the items up front into a collection before processing them one at a time. ForEach-Object expects the items to be streamed via the pipeline, thus lowering the memory requirements, but at the same time, taking a performance hit. Following are a couple of tests to highlight the differences between these:

$time = (Measure-Command {

    1..1E4 | ForEach-Object {

        $_

    }

}).TotalMilliseconds

 [pscustomobject]@{

    Type = 'ForEach-Object'

    Time_ms = $Time

 }

 

$Time = (Measure-Command {

    ForEach ($i in (1..1E4)) {

        $i

    }

}).TotalMilliseconds

  [pscustomobject]@{

    Type = 'ForEach_Statement'

    Time_ms = $Time

 }

Image of command output

As expected, the ForEach statement, which allocates everything to memory before processing, is the faster of the two methods. ForEach-Object is much slower. Of course, the larger the amount of data, the more risk you have of running out of memory before you are able to process all of the items. So be sure to take that into consideration.

To throw another curve ball into this, check out this alternate approach to ForEach-Object. This time, we'll use the InputObject parameter (this is the parameter used in the pipeline process):

$Time = (Measure-Command {

    ForEach-Object -InputObject (1..1E4) {

        $_

    }

}).TotalMilliseconds

 [pscustomobject]@{

    Type = 'ForEach-Object_Param'

    Time_ms = $Time

 }

Image of command output

Wow, that was fast! Why am I not talking this up instead of focusing on ForEach? Although this seems like the fastest of the three approaches, the major (yes, major!) issue is that we are being deceived into thinking that it just processed everything in an amazing amount of time. But the fact is that all we did was pass the entire collection to the script block one time—and that was it.

ForEach-Object -InputObject (1..1E4) {

    $_.GetType().FullName

}

Image of command output

Well, it was worth a shot to squeeze a little more speed out of this. But in the end, we get something that is completely unusable—even if we did want to send it down the pipeline. 

ForEach-Object also allows us to specify Begin, Process, and End script blocks that we can use (similar to an advanced function) to set up our environment, process each item, and then do something (such as clean up at the end of the command).

Get-ChildItem -Force | ForEach-Object -Begin {

    Write-Verbose "Begin block" -Verbose

} -Process {

    If ($_.length -gt 555) {

        Write-Verbose "Process block" -Verbose

        $_

    }

} -End {

    Write-Verbose "End block" -Verbose

}

Image of command output

Here you see that the Begin block kicks off first, followed by all of the items that I am processing and filtering, with the End block being processed last. If I wanted, I could then pass this to another cmdlet, such as Export-CSV. You couldn’t come close to doing this type of action by using the ForEach statement.

So which one do you use? Well, the answer is, “It depends.”

You can iterate through a collection of items by using either the ForEach statement or the ForEach-Object cmdlet.

  • ForEach is perfect if you have plenty of memory, want the best performance, and do not care about passing the output to another command via the pipeline.
  • ForEach-Object (with its aliases % and ForEach) take input from the pipeline. Although it is slower to process everything, it gives you the benefit of Begin, Process, and End blocks. In addition, it allows you to stream the objects to another command via the pipeline.

In the end, use the approach that best fits your requirement and the capability of your system.

Follow the Scripting Guys on Twitter and Facebook. If you have any questions, send an email to the Scripting Guys at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. 

Boe Prox, Windows PowerShell MVP and Honorary Scripting Guy

PowerTip: Use PowerShell to Locate the Help File You Need

$
0
0

Summary: Learn how to use Windows PowerShell to find the Help file you need.

Hey, Scripting Guy! Question How can I figure out the exact name of the Help file that I am looking for about sessions?

Hey, Scripting Guy! Answer Use a wildcard character with Get-Help to narrow down the scope of the Help files:

Get-Help about_*session*

 

Name                              Category  Module                    Synopsis

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

about_PSSessions                  HelpFile                            Describes Windows PowerShell sessions (PSSessi...

about_PSSession_Details           HelpFile                        Provides detailed information about Windows Po...

about_Remote_Disconnected_Sess... HelpFile               Explains how to disconnect from and reconnect ...

about_Session_Configurations      HelpFile                      Describes session configurations, which determ...

about_Session_Configuration_Files HelpFile                   Describes session configuration files, which c...

about_CIMSession                  HelpFile                             SHORT DESCRIPTION

Handling Errors the PowerShell Way

$
0
0

Summary: Trevor Sullivan talks about handling errors in Windows PowerShell.

Microsoft Scripting Guy, Ed Wilson, is here. Today we have guest blogger and Windows PowerShell MVP, Trevor Sullivan...

Microsoft Scripting Guy, Ed Wilson, just wrote a post about how to use the Try-Catch-Finally blocks in Windows PowerShell. But have you ever wondered if that was the only way to handle errors? It turns out that although it’s a great way to handle errors, there are still other options!

If you’re coming to Windows PowerShell from a software development background, you’ll most likely pick up on Try-Catch-Finally pretty easily. On the other hand, if you’re new to scripting, or you are a curious, knowledge-driven individual, you might want to consider what we’re talking about today.

Common parameters

When Windows PowerShell 2.0 came out, a new concept was introduced, called Advanced Functions. This concept allows you to develop commands that have the same feel as compiled cmdlets, while writing them in Windows PowerShell script syntax. One of the benefits of developing cmdlet-style commands instead of basic functions, is that they offer a few “common parameters.” Two of these common parameters are related to error handling: -ErrorAction and -ErrorVariable.

For more information about common parameters in advanced functions and compiled cmdlets, run this command at the Windows PowerShell prompt:

Get-Help -Name about_CommonParameters;

ErrorVariable Parameter

Normally, if you run a Windows PowerShell command and an error occurs, the error record will be appended to the “automatic variable” named $error. When you use the -ErrorVariable parameter in a call to a command, the error is assigned to the variable name that you specify. It’s important to note that even when you use the -ErrorVariable parameter, the $error variable is still updated.

By default, the -ErrorVariable parameter will overwrite the variable with the name that you specify. If you want to append an error to the variable, instead of overwriting it, you can put a plus sign (+) in front of the variable name. Let’s take a look at an example:

Stop-Process -Name invalidprocess -ErrorVariable ProcessError;
$ProcessError;
Stop-Process -Name invalidprocess2 -ErrorVariable +ProcessError;
if ($ProcessError) {
    ######## Take administrative action on error state
}

Image of command output

ErrorAction parameter

The -ErrorAction common parameter allows you to specify which action to take if a command fails. The available options are: Stop, Continue, SilentlyContinue, Ignore, or Inquire. If you’re developing a Windows PowerShell workflow, you can also use the Suspend value. However, advanced functions cannot be suspended.

When you specify the ErrorAction parameter during a call to a command, the specified behavior will override the $ErrorActionPreference variable in Windows PowerShell. This variable is part of a handful of variables known as “preference variables.” By default, Windows PowerShell uses an error action preference of Continue, which means that errors will be written out to the host, but the script will continue to execute. Hence, these types of errors are known as “non-terminating” errors.

If you set $ErrorActionPreference to Stop or if you use Stop as the parameter value for -ErrorAction, Windows PowerShell will stop the script execution at the point an error occurs. When these errors occur, they are considered “terminating errors.”

As an example, if you want to stop the execution of your Windows PowerShell script when an error occurs during a call to Stop-Process, you can simply add the -ErrorAction parameter and use the value Stop:

Stop-Process -Name invalidprocess -ErrorAction Stop;

Image of command output

If you want to suppress the errors from being displayed, you can use the value SilentlyContinue, for example:

Stop-Process -Name invalidprocess -ErrorAction SilentlyContinue;

Image of command output

You can also combine the ErrorAction and ErrorVariable parameters, such as in this example:

Stop-Process –Name invalidprocess -ErrorAction SilentlyContinue -ErrorVariable ProcessError;

If ($ProcessError) {

    ####### Something went wrong

}

Image of command output

We have explored the use of two Windows PowerShell common parameters, ErrorAction and ErrorVariable. I hope that this post has enlightened you about the use of these variables and how to use them to direct the execution flow of your scripts. Thank you for reading, and I will see you next time!

~Trevor

Thank you, Trevor, for taking the time to write this explanation and sharing it with our readers.

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: Find Information About ErrorActionPreference

$
0
0

Summary: Find information, beyond the basics, for the Windows PowerShell variable ErrorActionPreference.

Hey, Scripting Guy! Question How can I use Windows PowerShell to see information, beyond only the value, for the variable ErrorActionPreference?

Hey, Scripting Guy! Answer Use the Get-Variable cmdlet and pipe the results to the Format-List cmdlet:

Get-Variable ErrorActionPreference | Format-List *

Note  When you use the *variable cmdlets, you do not specify the initial dollar sign.
So it is represented as ErrorActionPreference not $ErrorActionPreference.

Use Windows PowerShell to Prepare for Migration from SharePoint 2007

$
0
0

Summary: Marc Adam Carter talks about using Windows PowerShell to smooth the way for a large SharePoint 2007 migration.

Microsoft Scripting Guy, Ed Wilson, is here. Today our guest blogger is Marc Adam Carter...

If you’re responsible for administering a SharePoint 2013 or SharePoint 2010 farm, I’d have to say that things are looking pretty good right now with the availability of management tools. The SharePoint administration lawn is seriously greener on these farms.

Let’s face it, even if you haven’t yet migrated from an older platform, such as Microsoft Office SharePoint Server 2007 (MOSS 2007), you’re already likely aware of the library of 500 plus SharePoint-specific cmdlets that are exposed in the SharePoint Management Shell. This proprietary shell is derived from a special base class (SPCmdlet), which is installed on top of the core Windows cmdlets.

The SPCmdlet base class is included in the Microsoft.SharePoint.PowerShell namespace, which gets installed as part of the SharePoint binaries. Although this is less useful information for MOSS 2007 admins, it’s valuable to understand, and something I hope to clarify within this blog post.

So if you are like me, with one foot still in the Microsoft Office SharePoint Server 2007 (MOSS 2007) world, most of your administrative work occurs within the Central Administration pages or by using the STSADM command-line tool.

These tools are sufficient for managing our farm, but we’re preparing to upgrade soon and want to migrate content from our existing environment to our new one. As part of our content migration process, we want to spend a little time cleaning up sites so we don’t simply move stale or unused content into our new farm. We also want to identify inconsistencies that are occurring between content and our governance policy. For example, we require that all libraries and lists include a brief description to help staff identify the content, intent, or purpose of a library or list.

Leveraging the .NET Framework

Unfortunately, neither Central Administration nor STSADM are extremely effective for easily providing the details we’re looking for. Although we don’t have access to built-in SharePoint PowerShell cmdlets in MOSS 2007, we can still reference the .NET Framework and the Microsoft.SharePoint assembly to create our own scripts so that we can produce quick customizable reports.

Before diving into the script I put together, I’m compelled to apologize for it lacking a polished, ready-to-ship quality, which is standard for the level of contributions to this site. As with a large majority of scripts in my personal library, I write with the intent of efficiently accomplishing a goal. I may use a script like this one a couple times, and occasionally refer back to it. But for me, there’s no advantage of rolling it up into a function or module. It may not be the shiniest tool in my Windows PowerShell tool belt, but it’s one of my favorites.

Dependencies

There are two SharePoint requirements for this script to function as expected:

  • You'll need to run this script with an account that is a member of the SharePoint administrators group. Members of the SharePoint administrators group have rights to view and manage all sites created on their servers.
  • You'll need to use the Microsoft.SharePoint core class. Similarly to what I mentioned earlier, this namespace provides a path for interacting with site collections, websites, lists, and list items. The base assembly is added to a system’s Global Assembly Cache (GAC) when SharePoint is installed. So trying to execute the script from a system without SharePoint installed will result in the following error message, which tells you it couldn’t locate the assembly: “Verify that the assembly containing this type is loaded.”

Initial variable declarations

First things first. We need to load the .NET Assembly and define a few initial variables that we’ll use later in the script.

 [void] [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

$testDate = (get-date).AddMonths(-6)

$array = @()

$SPSite = New-Object Microsoft.SharePoint.SPSite("http://contoso.com/")

Because one of the goals is to identify old or stale content, I’m defining a DateTime variable ($testDate) on line #2 to use as a comparison later when I have some objects with dates. The other static configuration is to specify the URL of the web application you want to query. The script will iterate through all site and subsite collections found under this URL.

Image of command output

Drilling into site collections

We’ll traverse through the site collections by using a couple nested ForEach loops to drill down to the website level so we can inspect the various objects of the SPList class. Entering the first ForEach loop, we’ll define the top-level site and create a temporary site collection variable ($SiteCollection). This will return all websites within the site collection in the inner ForEach loop by referencing the AllWebs property.

But before entering the inner ForEach loop, we’ll write the URL of the site collection we’re currently inspecting to the screen ($SPSiteCollection.url), so we get some feedback while running the script to see where we’re at.

We’ll also create a string variable ($SiteUrl) that we’ll use when outputting the results to a CSV file later in the outer loop. Within the inner ForEach loop, we’ll define a temporary site variable ($SPWeb) by using the OpenWeb method and passing it the relative path, then returning the website associated with the URL.

We’ve now arrived at the website level, and we can start collecting information about our SharePoint objects (for example, lists, document libraries, and picture libraries). The final step we’ll perform in the inner loop is to populate our array with the selected properties.

ForEach($Site in $SPSite.WebApplication.Sites){

 $SiteCollection = New-Object Microsoft.SharePoint.SPSite($Site.Url)

 $SiteCollection.url

 $SiteUrl = $($SiteCollection.ServerRelativeUrl -replace("/","_"))

 ForEach($SubSite in $SiteCollection.AllWebs){

  $SPWeb = $SiteCollection.OpenWeb($SubSite.ServerRelativeUrl)

  $array += $SPWeb.Lists | Select-Object BaseType, BaseTemplate, Title, RootFolder, Description, Hidden,

   DefaultViewUrl, Author, ID, ItemCount, Created, LastItemModifiedDate, HasUniqueRoleAssignments, NoCrawl

 }

I select only the properties I’m concerned about for the scope of this task, but after you’ve defined your website variable ($SPWeb), you can use the Get-Member cmdlet to inspect the methods and properties of the SPList class.

Image of command output

Package results and send to CSV file

We’ve traveled down to the object level and filled our SharePoint bucket with details about each SPList object. The last stop on this ride is to package those results into a format that is easy to use and one that can be handed off to our site administrators and data owners to consume.

At this point, we’ve exited our inner loop and passed the contents of our array along the pipeline. The last little bit of “trickery” is to include some logic to help identify the problematic objects we’re looking for. To accomplish this we’ll use Select-Object to create a calculated property column labeled “Questionable.”

To build this column, we’ll evaluate a few properties within a hash table to see if they meet our criteria, and indicating that we have a suspect object. After the calculated column, we use the asterisk ( * ) to specify that we want all the other objects from the array. We then pass those objects to Export-CSV. The following table itemizes a breakdown of the evaluation criteria that is used in the calculated column:

Evaluation

Meaning

($_.Hidden)

Object is hidden

($_.ItemCount -eq 0)

Object contains no items

($_.LastItemModifiedDate -lt $testDate)

Object hasn’t been modified since before $testDate

($_.Description -eq "")

Object has no description

$array | sort DefaultViewUrl | Select-Object @{l='Questionable';

  e={if(($_.Hidden) -or ($_.ItemCount -eq 0) -or ($_.LastItemModifiedDate -lt $testDate) -or ($_.Description -eq "")){$True}Else{$False}}}, * |

  Export-Csv "C:\Site-Prep\$($SPSite.hostname)$($SiteUrl).$((get-date).GetDateTimeFormats()[5]).csv" -NoTypeInformation

$array = @()

Image of command output

Because we’ll repeat this process for each site collection within a web application, the script outputs a separate CSV file for each site collection, and lists all the subsites contained within that site collection. This allows us to inspect content for a specific site collection, depending on your topology per content database.

The following image provides an example of one of the CSV files generated by the script. Note the first column is our calculated column, which provides a quick reference to potentially low-hanging fruit.

Image of file

Following is the complete script:

[void] [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

$testDate = (Get-Date).AddMonths(-6)

$array = @()

$SPSite = New-Object Microsoft.SharePoint.SPSite("http://contoso.com/")

ForEach($Site in $SPSite.WebApplication.Sites){

 $SiteCollection = New-Object Microsoft.SharePoint.SPSite($Site.Url)

 $SiteCollection.url

 $SiteUrl = $($SiteCollection.ServerRelativeUrl -replace("/","_"))

 ForEach($SubSite in $SiteCollection.AllWebs){

  $SPWeb = $SiteCollection.OpenWeb($SubSite.ServerRelativeUrl)

  $array += $SPWeb.Lists | Select-Object BaseType, BaseTemplate, Title, RootFolder, Description, Hidden,

   DefaultViewUrl, Author, ID, ItemCount, Created, LastItemModifiedDate, HasUniqueRoleAssignments, NoCrawl

 }

 $array | sort DefaultViewUrl | Select-Object @{l='Questionable';

  e={if(($_.Hidden) -or ($_.ItemCount -eq 0) -or ($_.LastItemModifiedDate -lt $testDate) -or ($_.Description -eq "")){$True}Else{$False}}}, * |

  Export-Csv "C:\Site-Prep\$($SPSite.hostname)$($SiteUrl).$((get-date).GetDateTimeFormats()[5]).csv" -NoTypeInformation

 $array = @()

}

I hope you find this information useful and that it helps you with your SharePoint migration. Cheers!

~Marc

Thank-you, Marc, for your knowledge and time and for sharing with our readers.

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: Count a Range of Seconds with PowerShell

$
0
0

Summary: Use Windows PowerShell to count a range of seconds.

Hey, Scripting Guy! Question How can I use Windows PowerShell to count a range of seconds of increasing duration?

Hey, Scripting Guy! Answer Use the range operator to create a range of numbers, then pipe the results to the ForEach-Object cmdlet
          inside a script block call Start-Sleep:

1..5 | ForEach {Start-Sleep -Seconds $_ ; "$_ seconds"}

An End of Week Treat: Mini-Scripting Games

$
0
0

Summary: Windows PowerShell MVP, Jim Christopher, shares a mini-Scripting Games event from the Charlotte Windows PowerShell User Group.

Microsoft Scripting Guy, Ed Wilson, is here. Welcome today, guest blogger, Jim Christopher. Jim is a Windows PowerShell MVP and the leader of the Charlotte Windows PowerShell User Group. He was instrumental in creating and hosting two Windows PowerShell Saturdays in Charlotte, and he is also an all-around nice guy. Let’s see what Jim has to say about himself…

I am a four-time Windows PowerShell MVP, and I help run the Charlotte PowerShell Users Group. I currently own and operate Code Owls, LLC, a small software and services company focused on automation and integration projects. I maintain a blog at beefycode—serving all of your beefy code needs, and you can follow my inane ramblings on twitter (http://twitter.com/beefarino). If you’re a real glutton for punishment, you can find some of my work at: GitHub: Jim Christopher, beefarino.

Photo of Jim Christopher

Now on to the little Scripting Games...

Communities are hard. They’re hard to start, and they’re harder to keep going. The Charlotte PowerShell User Group has been blessed with a strong core membership in addition to regular attendance by the Scripting Guy and Scripting Wife. But there is something else that keeps members coming back.

We’ve all but abandoned the expert-comes-in-and-presents-over-pizza format. It was far too difficult to find speakers who could address the needs of more than a few members. Instead, our regular meetings now take the form of a short Scripting Game. These games are simple to put together, easy to run, and they benefit every attendee from the Windows PowerShell noob to the MVP.

In this post, I will write about our most recent little game in June 2014. You'll learn about how I designed it, how it was run, and the end effect on the group. My goal in writing this is to reach out to other community organizers who may be struggling, and to get other users groups to organize their own little Scripting Games.

Designing a little Scripting Game

There are a few key things to keep in mind when designing a little Scripting Game.

The main objective of a little Scripting Game is to get your group members thinking and tinkering.

They need a problem to solve that requires some effort and strategy. Generally, I try to focus the game on a very general technology with which all members would be familiar, such as the file system. Alternatively, I’ll choose a focus that I wouldn’t expect any member to have experience with, such as image data processing. I’ve found both to be equally effective at getting members actively scripting. For our June meetup I came up with a simple scenario that offered creative leeway:

Write a script that updates a specific file periodically. At the same time, the script should try to prevent other scripts from updating their own files.

I like this scenario for several reasons. First, it requires members to divide their attention. Their script has two opposing problems to deal with:

  • They need to update the file to win, but they also need to prevent others from updating their files. Moreover, they need to cope with the fact that other scripts will be attempting to stop their script in devious ways.
  • The core technologies involved in the game are very accessible in Windows PowerShell.

I could immediately think of several ways to solve the problems. I might keep my script running by “forking” it—that is, by having the script spawn another Windows PowerShell process that starts the script again, or perhaps by running parts of my script as jobs. I might try to prevent other scripts from updating their files by killing any Windows PowerShell process that isn’t my own or by modifying ACLs on the files they’re trying to write.

In short, this game has a lot of potential solutions, and their effectiveness depends entirely on the tactics used by other scripters. It’s a slam dunk for a little game!

The little Scripting Games need to be able to be completed in an hour or so.

This really limits the level of complexity you can put into the game’s objective. I’ve learned to keep little Scripting Games more open-ended than, say, an Iron Scripter or week-long Community Games event. Fewer requirements also allow scripters to be more creative with their approaches. The scripter’s goal should be to solve a problem, not to check requirements off a list for a judge.

It needs to be fun.

This is vital. No one at the game wants to spend an evening doing more work. If they did, they’d have stayed at work. So I try to come up with games that foster a sense of competition. Sometimes it is direct, such as this game from June or one of the games we ran last year where we wrote scripts that played rock/paper/scissors against one another. In other cases, the competition is more subjective, and we have a set of judges determine a winner.

In any case, scripters know that they are expected to show their script and explain their approach to the group. This helps everyone learn from everyone else in a safe, constructive environment.

Finding the right combination of these elements can be difficult. It help me to brainstorm ideas with members of the group and keep a running list of ideas from which to draw.

Running a little Scripting Game

After you have selected a problem for your little game, you’ll need to think about how you’re going to run it. Part of this is building the prerequisites for the game. For instance, in our June meetup, I needed a server image on which to run the scripts because I really didn’t want our group members trashing my laptop. So I set up a disposable Microsoft Azure instance of Windows Server 2012 R2 that they could trash instead.

In other events we had virtual Active Directory labs available. Finding these resources and making them available can be the hardest part of running the game, and it typically takes the longest chunk of preparation time.

On the night of the game, we follow a simple procession:

1. Cover the general rules

2. Discuss the problem

3. Script!

4. Combat (or judging)

5. Present the scripts

Before every game I go over the general rules for the game. These are for newcomers mostly, but they also serve as a gentle reminder to our regulars that the game is meant to be fun. The rules are simple:

  • Use any resource at your disposal.
  • Work in teams or alone.
  • For games involving judges, their decisions are final.
  • Complaining is not allowed.
  • You must share your solution with the group.

When we’re all on the same page with regard to expectations, we dig in to the game’s problem. This is where I spell out the specific requirements for the game and explain how a winner is determined. For our June meetup, these requirements were as follows:

1. Write a script that does the following:

  • Updates a file periodically. The file should be found at the path C:\game\<yourname>.txt. The contents of the file do not matter, only the last update time.
  • Inhibits other scripts from updating the file.

2. Use FTP to transfer your script file to the Azure VM.

3. The winner is determined by who is the user with the most recently updated file after a specified period of time.

After everyone understands the game parameters, we enter the scripting phase. This can take anywhere from 15 to 60 minutes depending on the game. In June, we had some scripters submit scripts in less than 15 minutes; others wanted more time after an hour. I find it best to set a hard upper limit on time; otherwise, some scripters will try to boil the ocean to solve the problem.

Image of members

When the scripting is complete, the game enters the combat/judging phase. For the June script battle, this was a simple matter of firing up each script in its own Windows PowerShell process and letting them run unattended for a few minutes. In other games, this involves collecting the scripts for judging.

In either case, the most important factor is that there be a clear winner. This doesn’t always happen of course, and there are various ways to cope with that situation. I personally like setting an arbitrary metric for tie-breakers, such as “the fewest lines of script wins.”

When the battle is over, it’s time for scripters to learn from each other. Typically the winner starts. The winning script is displayed, and the scripter stands up and walks the group through the script and their thoughts behind it.

This is by far my favorite part of the evening. I’m always shown something new, either an approach I’ve never considered or a language feature of which I was unaware. In June, I learned more than I ever wanted to know about ACL management!

And the learning doesn’t stop with the event. I make the problems and scripts available to all of the group members via our Charlotte PowerShell Users Group Meetup site.

The untapped potential

I would love to see other Windows PowerShell Users Groups start running little Scripting Games. The benefits are real and immediate for your members, and it offers a new bond in your community that you won’t get any other way—the mix of competition and support between members is simply magical.

Which makes me wonder about what could come next...

If your local Windows PowerShell Users Group is running games, as a community we can get organized. We can have tournaments, brackets, titles, and badges. The opportunities for learning and sharing knowledge in this framework would be amazing.

The community has done itself a great service with the official Scripting Games. So who’s interested in taking it to the next level?

~Jim

Thank you, Jim. This is soooooo cooooool!

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: How Long Has My Computer Been Running?

$
0
0

Summary: Learn a one-liner Windows PowerShell command to see how long a computer has run.

Hey, Scripting Guy! Question How can I use Windows PowerShell to find out how long my computer has been running
          since last boot up without writing a script?

Hey, Scripting Guy! Answer Use the Win32_OperatingSystem WMI class and the LastBootupTime property,
          and then subtract the value of the current date/time that comes from Get-Date:

(Get-Date) - (Get-CimInstance Win32_operatingSystem).lastbootuptime

Weekend Scripter: Top Ten PowerScripting PodCasts

$
0
0

Summary: Windows PowerShell MVP, Teresa Wilson, talks about the top ten PowerScripting podcasts.

Microsoft Scripting Guy, Ed Wilson, is here. This weekend we have a very special guest blogger. You guessed it. Teresa Wilson, aka The Scripting Wife, will share her thoughts with you. Take it away Teresa...

Happy Saturday everyone. Things have been pretty busy here in the Scripting house. I feel like I have not been in touch with you for a while. My apologies. Today's topic is my career as the scheduler for the PowerScripting podcasts, and I want to share my top ten most memorable guests, subjects, or episodes.

As some of you may know, I recently resigned my post as the scheduler for guests for the PowerScripting podcasts. It was a tough decision to make, but sometimes we have to make tough decisions. I will miss the fun and interesting emails I have had with guests, but I also know that I am not going anywhere and I will still be around with the PowerShell community.

I am heavily involved in helping people start PowerShell User Groups and assisting in any way I can to keeping them up and running. I am also the treasurer for PowerShell.org. I am available to assist the PowerShell community. Simply reach out to me!

I got to thinking about the last nearly four years of PowerScripting fun, and I thought you might enjoy some of the highlights of the years. The first guest I scheduled was for Episode 131, and we are now on Episode 275 or so. Therefore, I came up with my ten most memorable guests, subjects, or episodes from the PowerScripting podcasts.

  1. The very first guest I booked was Sean Kearney. This was on November 11, 2010. (In case you are wondering how I came to be in the position of scheduler...
    Jon and Hal had a couple of weeks where they were so busy that they did not have a guest invited to the show, so they just talked about Windows PowerShell between the two of them. My background is in accounting and I am very detail oriented, so I offered to schedule guests if they would provide me a list of names of people to invite. They also said I could make suggestions. Which led me to say, "How about Sean?"
  2. On January 13, 2011, Hal suggested I invite @Beefarino. I thought, "Hmmmm...I wonder who this could be?" So I did my research and tracked down Jim Christopher. At this time in life, I had read a few books that Ed (Scripting Guy) had written and I knew a little bit about Windows PowerShell, but oh my gosh, Jim is so smart. He blew me away. Today, Jim is one of my favorite people, and luckily, I get to see him once a month at the Charlotte PowerShell User Group meetups, with which I help him as much as I can.
  3. On various dates, we had the unbeatable, Jeffrey Snover on the show. Jeffrey is such an all-around nice guy and interesting person. I love to sit back and listen to him. One of his most endearing qualities is his genuine interest in hearing from the Windows PowerShell community. Things that work, things that don’t, and things in between. He has been the guest by himself when new versions of Windows PowerShell become available. And he has been on the show with the winners of the Scripting Games.
  4. Speaking of the winners of the Scripting Games, my most memorable are Bartek Bielawski, Glenn Sizemore, and Boe Prox. There are many great people who have been the winners of the Scripting Games, but there is a special story about each one of these guys that make them hit this top ten list.
  5. Alan Renouf and Steven Murawski have or have had podcasts of their own, so it is always memorable when either of these guys are the guest. Both guys are personal friends and they are amazing in their specialties in Windows PowerShell.
  6. One of my proudest moments, was while attending TechEd a couple years ago. We were sitting at the Ask the Experts table, which is fun because it is like musical chairs. You have the experts chatting among themselves until someone comes along with a question or simply to say hello.
    Hal Rottenberg mentioned to me that he would like to interview a SME (subject matter expert) from Symantec. I stored that info in the back of my mind, thinking I would research it after TechEd, when lo and behold, the gentleman I was conversing with at the ATE table admitted that he worked for Symantec. I was so excited. I told him what Hal was looking for and asked him if he knew who to talk to, and if he could introduce me. I was really amazed when he said it was his team and he would probably be the one to give the interview. Kirk Freiheit is one name and one awesome person, I will never forget.
  7. Don Jones, as most everyone knows, is one of my favorite people on this earth. I am not really impressed with the current actor portraying James Bond in the movies, and I have said many times that Don should be the new 007. Thus, me listing him here in the number 7 slot.
    Now I am not being superficial. I am not referring to Don’s physical person, but his demeanor. Don is always a perfect gentleman, and he is always, always willing to help in any possible way he can. He has been a guest on the podcast numerous times, in addition to co-hosting when needed. To me, Don Jones is the true epitome of gracious helpfulness, and he is an awesome guest or co-host for the podcast.
  8. One of the more fun podcasts was on May 23, 2012, when Hal’s Wife and I were the guests. The subject was being a Windows PowerShell wife. There was not much technical information shared, but we had a great time.
  9. How could I ever forget being able to email with the likes of Mark Minasi, Greg Shields, Lee Holmes, Jason Helmick, Mark Russinovich, and Jeffery Hicks? Some of the world’s top Who’s Who in the IT industry, and I get to say I emailed with each and every one. I also can call them all friends (except Russinovich, but I do have a photo of him autographing my book at TechEd).
  10. Last but not least, and my very favorite guest is none other than my husband, Ed Wilson, Microsoft Scripting Guy.

So there you have it. Thanks for the memories, PowerScripting podcast.

~Scripting Wife

Thanks, Teresa. I invite you to follow me on 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: PowerShell Summit Europe 2014

$
0
0

Summary: The Scripting Wife shares information about Windows PowerShell Summit Europe 2014.

Hey, Scripting Guy! Question Do you have any information about the Windows PowerShell Summit Europe 2014?

Hey, Scripting Guy! Answer Windows PowerShell Summit 2014 is Sept 29–October 1, 2014 in Amsterdam.

One nice thing about this smaller event is that there is only one track, so you don’t have to choose between sessions that you want to attend and what you will miss.


Weekend Scripter: Hurrah for Curah

$
0
0

Summary: Teresa Wilson (aka Scripting Wife) talks about how Microsoft Curah solved her search issue.

Microsoft Scripting Guy, Ed Wilson, is here. Windows PowerShell MVP, Teresa Wilson is back with us today to share information about Curah.

One of the problems with trying to find technical information is...well...trying to find it in the first place. It seems that I can spend hours trying to find just the right article to solve an issue. Search engines are helpful at times, but if I do not know the right thing to search for, I am doomed. Going to a specific page, or set of pages, such as TechNet or MSDN, is OK—but there are so many pages, and many times they have conflicting information (depending on what version I need help with). This leaves me still stuck and working my way through tons of material.

Luckily, there is a new tool that can solve many of these issues. The tool is Curah, and it is way cool. The idea is that people choose the best sources of content about a given subject and share it via a content curation. Curated content is nice because it is selected from among the hundreds of thousands of items that a typical Bing search returns. Because the people making the curations are experts in their field, I can have confidence that this is what I really need.

I am not in favor of reinventing the wheel. Therefore, this will not be a very long post. But hopefully, it will provide you with a lot of useful information.

Basically, Curah is a place for you to create your own site of useful websites and resources for others to view. You can add your own notes and descriptions. I think of it is a notebook that you can share.

Microsoft has a website called Curah. You can go to a Curah page and search for existing pages or you can create your own Curah. Here is the description of Curah from TechNet: What is Curah!, and how do I get started? Pop on over to the Curah FAQ and take a look, if you still have questions, you can post them on the Forum.

The really cool thing is that there are a lot of Windows PowerShell resources highlighted on Curah. At this writing, there are 145 results for curated Windows PowerShell content. There is even a series of curations that were created by the Scripting Guy, Ed Wilson.

So check out the curated content at the Microsoft Curah site. You will be glad you did.

~Teresa

Thanks, Scripting Wife! 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: Generate Random Beeps with PowerShell

$
0
0

Summary: Use Windows PowerShell to generate random beeps.

Hey, Scripting Guy! Question How can I generate random beeps by using Windows PowerShell?

Hey, Scripting Guy! Answer Create a range of numbers between 190 and 8500 that will determine the tone.
          Use the Get-Random cmdlet to choose a random number of tones. Pipe the results to the 
          ForEach-Object cmdlet, and call the Beep static method from the system.console class.
          The first number determines the tone, and the second number determines the length of the tone.
          Here is an example of this technique:

190..8500 | Get-Random -Count 35 | ForEach {[console]::Beep($_, 150)}

PowerShell String Theory

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to work with strings.

Microsoft Scripting Guy, Ed Wilson, is here. This has been an exciting week around the Scripting Household. From our lanai, we can see several little rabbits hopping around—they seem to like the clover. We have seen some butterflies (which in past years, we have not seen), and the hummingbirds are back. It is a great time to be out and about. Sitting in a swing, observing nature is a fundamental that helps me keep a positive mental outlook.

Another fundamental is working with strings in Windows PowerShell. In the past (like back in the VBScript days), I hated working with strings. I could do it, but it did not seem like much fun to me. I would rather pull weeds out of the garden than spend a day manipulating VBScript strings. Luckily, Windows PowerShell makes that a bit easier to handle.

A string is an object

By now, you have probably heard that everything in Windows PowerShell is an object. This is one reason why the Get-Member Windows PowerShell cmdlet is so very important. It provides insight into the objects with which one might be confronted. Here is an example of piping a string object to Get-Member and looking at the methods that are available:

Image of command output

String objects

String objects have a single property. Properties describe things. Therefore, I can use the available string property to describe the string to me. What if I want to describe what am I most interested in? In this example, I am interested in how long is the string. So the property I have available to me is Length as shown here:

PS C:\> $a = "string"

PS C:\> $a | Get-Member -MemberType property -Force

   TypeName: System.String

 

Name   MemberType Definition

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

Length Property   int Length {get;}

 

PS C:\> $a.Length

6

Strings have lots of methods

Windows PowerShell strings have lots of methods. Again, I can use the Windows PowerShell Get-Member cmdlet to list the string methods. These are shown here:

Image of command output

The string object is well documented on MSDN (for more information, see String Class), and MSDN is the primary source of documentation for all the methods and other members of the objects. Most of the methods are really easy to use. For example, to find the position of a particular letter within a string, I use the IndexOf method. Here is an example of that technique:

PS C:\> $a = "strings"

PS C:\> $a.IndexOf("s")

0

PS C:\>

            PS C:\> $a = "strings"

PS C:\> $a.IndexOf("s")

0

    Note  The IndexOf method is zero based. This means that it begins counting at zero. The Length property is 1 based,
    so it begins counting with 1.

The IndexOf method has a couple of overloads. This means that the same method can be used in different ways. As I showed previously, the basic way to use IndexOf is to tell it to look for a letter. When it does this, it begins looking at the first position (index 0). When it finds a match, it is done.

The second way to use IndexOf is to tell it what to look for and where to begin looking. In this example, the word strings is seven characters long. The first position that contains the letter “s” is in position zero. Therefore, if I tell it to begin looking for the letter “s” beginning with the second letter (index position 1), it will find the letter “s” in index 6 (the seventh position in our word). This is shown here:

PS C:\> $a = "strings"

PS C:\> $a.IndexOf("s",1)

6

PS C:\>

There is another way to use the IndexOf method that combines the first two ways.

 Image of text bubble

 Image of Dr. Scripto

The last way I want to look at using the IndexOf method today permits me to specify the letter I want to look for, the place I want to begin looking, and the number of characters that I want to search. After creating my string, I use the IndexOf method to look for the letter "s" beginning in position 1. (Remember this is the second letter in the string; and therefore, I miss the initial letter "s"). I tell it to seek from position 1 to position 5 (the second letter through the sixth letter, which in this case is the letter "g"). It returns -1. When the IndexOf method returns the number -1, it means that it did not find a match.

PS C:\> $a = "strings"

PS C:\> $a.IndexOf("s",1,5)

-1

The next time, I use the IndexOf method, I again specify the letter "s," and I again begin searching at the second letter (index 1). But this time, I search through to the seventh letter (index 6). This time, the IndexOf method returns 6, which means it found a match in the sixth index position. This is shown here:

PS C:\> $a.IndexOf("s",1,6)

6

PS C:\>

    Note  According to MSDN, it appears that there are at least 9 ways to use the IndexOf method.

There is your simple introduction to using Windows PowerShell to work with strings. String Week will continue 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: Select First Two Letters of String

$
0
0

Summary: Learn how to use Windows PowerShell select the first two letters from a string.

Hey, Scripting Guy! Question How can I use Windows PowerShell to remove the first two letters from a string?

Hey, Scripting Guy! Answer Use the SubString method, for example:

$a = “String”

$a.substring(2) 

Keep Your Hands Clean: Use PowerShell to Glue Strings Together

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about several approaches for concatenating strings by using Windows PowerShell.

Microsoft Scripting Guy, Ed Wilson, is here. This weekend, I was speaking about blogging and technical writing at the South Carolina Writers Workshop in Rock Hill, South Carolina. One of the cool things is a couple of people drove from Atlanta and from Raleigh, North Carolina to attend my sessions. It was great to see them.

If you hang out with The Scripting Wife on Facebook, you know that we also moved over the weekend. It is just across town, but still it is a major disruption. This morning I am sitting on the floor in our new apartment, with my Surface Pro 2 propped up on a cardboard box full of books, and I am listening to Chick Corea on my Zune. I have my Zune plugged in to an old pair of powered “computer speakers” to make an impromptu stereo. Here is a picture of my current workstation: 

Image of computer

I can’t find my Bose noise-cancelling headphones, or I would just use those. The nice thing is that our new apartment has free WiFi in the common areas, and the signal is strong enough in our apartment, so I am all set.

The cool thing about my Surface Pro 2 is that it, in fact, has Windows PowerShell. So I can write my blog post for today without any issues.

Joining strings

When it comes to the simple task of joining strings, Windows PowerShell offers multiple ways to accomplish this task. I know it can get somewhat complicated, but when I stop to think about it, the simple task of joining strings can get really complicated. For example, the easiest way to join two strings is to concatenate them. But even that choice has multiple options.

Concatenating strings

Let's take a look at how to concatenate (join together) a couple of strings. To do this, I will assign the strings to two variables. This is shown here:

PS C:\> $s = "This is a string"

PS C:\> $t = "a really cool string"

In Windows PowerShell the concatenation operator is also the one that is used for adding stuff together. So it sort of makes sense. To concatenate the string, I just add them together. Here is the command and the result:

PS C:\> $s + $t

This is a stringa really cool string

PS C:\>

WooHoo! It worked!

But wait. One might say it “messed up.” Actually, I wanted it to show up like that. Honest. Really. OK, maybe not.

What happens when concatenating two strings like that, is it glues them together. If I want a separator, I need to specify it. Here is my revision:

I use a comma and a space for my separator, and the output looks great:

PS C:\> $s + ", " + $t

This is a string, a really cool string

PS C:\>

Expanding strings

An easier way to concatenate the strings is to use double quotation marks because they automatically expand the contents of the variable. So, instead of multiple concatenation operators, all I need to do is put everything in a pair of double quotation marks. When I do that, I add my comma and my space inside the string. This can make it a bit difficult to read, but it works fine. This is shown here:

PS C:\> "$s, $t"

This is a string, a really cool string

PS C:\>

Substitution

Because the expanding string can become difficult to read, I often like to use substitution values and the format specifier. To do this, I create a string and parameters for place holders. My separator goes inside the string. Then I use the –f format operator and specify the values for {0} and {1}. This is shown here:

PS C:\> "{0}, {1}" -f $s,$t

This is a string, a really cool string

PS C:\>

Use the Join operator

Windows PowerShell has a Join operator that will glue strings together. It is a little funky and it takes a bit of practice to use, but when you understand it, it works well. Here is the way I first tried to use the Join operator:

PS C:\> $s -join $t

This is a string

PS C:\>

Needless to say, I was not impressed with the output. So I had to look up the about_Join topic in my online Help.

I learn that if I want to join the strings together, I need to put –Join at the beginning of the command as shown here:

PS C:\> -join $s, $t

This is a string

a really cool string

PS C:\>

Well OK, that worked. Sort of. But it does not look like what I had in mind when I wanted to join the two strings. It looks more like an array of strings, which I would pretty much have anyway. How about take number two:

PS C:\> -join ($s, $t)

This is a stringa really cool string

PS C:\>

This is what I was really expecting. It looks like I need to group the strings together, and then –Join will concatenate them. Groovy. But now I am back where I started. I need to figure out how to add a delimiter.

That is pretty easy. The online Help tells me that by default, there is no delimiter. But if I want a delimiter, I need to put it as the second argument to the operator. So here I go for attempt number four:

PS C:\> -join ($s, $t), ", "

This is a stringa really cool string

,

PS C:\>

Dude, that did not work either. Bummer.

I look at the Help topic a bit closer, and I discover that If I want to join a string with a specific delimiter, I put the string on the left side, and I put the delimiter on the right side. Attempt number five:

PS C:\> $s, $t -join ", "

This is a string, a really cool string

PS C:\>

And it works! Note that this time, I did not have to group my strings together—I was able to supply the strings as a simple array of strings.

So, like I said, the –Join operator is a little funky, but it does not take too much playing around to get it working properly.

That is all there is to joining strings. String Week will continue tomorrow when I will talk about using .NET Framework methods to join strings.

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 

Viewing all 2129 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>