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

Set Up a Lab with Windows PowerShell and Free Microsoft Software: Part 5

$
0
0

Summary: Preconfigure a virtual machine as a domain controller including Windows PowerShell Desired State Configuration and DHCP.

Hey, Scripting Guy! Question Hey, Scripting Guy!

I saw how we could build the virtual machines from a template. Were you teasing us about creating a new domain controller in this lab environment? I’d really love to see the script that would configure a domain controller in a lab virtual machine!

—RR

Hey, Scripting Guy! Answer Hello RR,

Honorary Scripting Guy, Sean Kearney, about to release the Kraken of Knowledge. Yes my good friend, with our current setup, we can set up that virtual machine to autostart to the point that we have a domain controller automatically!

     Note This post is the last in a five-part series. To catch up, read: 

At this point, we are creating a Windows PowerShell script. If you remember last time, for part of our set up, we have a Windows PowerShell script with the same name as a virtual machine for automatic setup.

In this case, I’m going to create a script for a virtual machine called EOT-DC01 for a future domain controller. We’re not simply going to spin up the Windows PowerShell cmdlet and create a new Active Directory; we are actually going to prepopulate some server features.

First, our server will need to have a static IP address configured. We’re also going to leverage all the new built-in cmdlets in Windows Server 2012 R2 to make this easier. For our lab, we’ll use 192.168.1.5, a 24-bit subnet mask (also known as 255.255.255.0), and a gateway of 192.168.1.1.

We are using two variables for the subnet mask because:

  • I’m lazy and I don’t want to write a cool function to convert the subnet.
  • We need two types of values for two types of cmdlets (the second are the DHCP cmdlets)

$DCIPAddress="192.168.1.5"

$DCGateway="192.168.1.1"

$DCPrefix=24

$DCSubnet="255.255.255.0"

Next on the list, we’ll define our domain name, folders for Active Directory, and a password for the safe-mode recovery for our domain. I fully recognize the password is sitting in clear text, and by all rights, this breaks every security rule! But remember, this is intended as use for lab environment. There are many great techniques for storing the password in a more secure manner if you need to, and you could easily adapt this script to it if you like it.

We are going to call our domain Contoso.local with an older NetBIOS name of CONTOSO. We’ll add a super secure password of P@ssw0rd.

$DomainName="Contoso.local"

$Netbios="CONTOSO"

$DB="C:\Windows\NTDS"

$Log="C:\Windows\NTDS"

$Sysvol="C:\Windows\Sysvol"

$Password='P@ssw0rd'

$SecurePassword=CONVERTTO-SecureString $Password -asplaintext -force

Coming up next is to assign an IP address. To configure an IP address in Windows Server 2012 R2, leverage the Get-NetAdapter and New-NetIPAddress cmdlets. Because this is a very simple server configuration, we do not need to filter out additional adapters.

Get-NetAdapter | NEW-NetIPAddress -IPAddress $DCIPAddress -Defaultgateway $DCGateway -Prefixlength $DCPrefix

To continue on with our domain controller, we need to add in some features. We need the Active Directory Domain Services binaries. I will also preload the bits for a DHCP server and Windows PowerShell Desired State Configuration.

Install-Windowsfeature AD-Domain-Services -includeallsubfeature -IncludeManagementTools

Install-WindowsFeature DHCP -IncludeAllSubFeature -IncludeManagementTools

Install-WindowsFeature DSC-Service -IncludeAllSubFeature -IncludeManagementTools

Now we’re going to predefine the scope for our DHCP server. This will be a simple scope of 100 potential addresses, starting at 192.168.1.100 and ending at 192.168.1.200. We are going to name it Contoso Lab DHCP Scope.

Because our domain controller will also be the primary DNS server in our lab, we can reuse the server IP address in our DHCP scope configuration:

$ScopeStart="192.168.1.100"

$ScopeEnd="192.168.1.200"

$ScopeSubnet="255.255.255.0"

$ScopeName="Contoso Lab DHCP Scope"

Then we need only add the cmdlets to create a DHCP scope:

ADD-DhcpserverV4Scope -StartRange $Scopestart -EndRange $ScopeEnd -SubnetMask $ScopeSubnet -Name $ScopeName

SET-DHCPServerV4Optionvalue -OptionID 6 -value $DCIPAddress

The following part is taken directly from the Windows Server 2012 R2 wizard for creating a domain controller. I have the variables at the top of script earlier so you can tweak them for your own needs and desires.

Import-Module ADDSDeployment

Install-ADDSForest -CreateDnsDelegation:$false -DatabasePath $DB `

-DomainMode "Win2012R2" -DomainName $DomainName -DomainNetbiosName $NETBIOS `

-ForestMode "Win2012R2" -InstallDns:$true -LogPath $Log `

-NoRebootOnCompletion:$false -SysvolPath $Sysvol -Force:$true `

-SafeModeAdministratorPassword $SecurePassword

Let’s keep in mind you need to authorize your DHCP server for it to be functional. But the Catch 22 is that you can’t authorize it in Active Directory until you have an Active Directory. This won’t happen until the Windows Server reboots. To ensure that this happens, we’ll populate an entry under the RunOnce key of our server to authorize the DHCP server after the reboot. 

NEW-ITEMPROPERTY "HKLM:Software\Microsoft\Windows\CurrentVersion\RunOnce\" -Name "PoshStart" -Value "PowerShell -command {ADD-DHCPServerInDC -DNSName EOT-DC01.contoso.local -IPAddress $DCIPAddress}"

Save this script in the C:\ISO folder as EOT-DC01.PS1, and then run the previous script for making a virtual machine from a template file like this:

NEW-VMFromTemplate –VMName EOT-DC01

In about 10 minutes (depending on your hard-drive speed and CPU), you should have a fully live and active domain controller for a domain called Contoso.local.

As a safety feature, the DHCP server is authorized, but the scope is not enabled should this inadvertently spin up on a production LAN.

At this point if you needed to add any newly created virtual machines to the domain, you can create a Windows PowerShell script with the Add-Computer cmdlet.

The cool part is that this method will work on the free Hyper-V Server 2012 R2 in addition to the licensed version and Windows 8.1.

If you’re feeling adventurous, you could try modifying it for earlier versions of Hyper-V, for example, Windows Server 2008 R2 and Hyper-V Server 2008 R2. You may have to parse DiskPart for the drive letters, or leverage a utility such as Virtual CloneDrive to mount the CDs.

Enjoy the Power, and let me know how it works out for you! If you’d like to save yourself from headaches from typing the scripts, you can download the main structure from the Script Center Repository: Deploy PreConfigured Virtual Machines in Hyper-V Server 2012 R2. Remember that to get this all running, you need to download Pronichkin’s Convert-WindowsImage.ps1 and the Windows Server 2012 R2 Evaluation Media.

I invite you to 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. See you tomorrow. Until then remember eat your Cmdlets each and every day with a taste dash of Creativity.

Sean Kearney, Windows PowerShell MVP and Honorary Scripting Guy 


A PowerShell Valentine’s Day Special

$
0
0

Summary: Microsoft Scripting Guy Ed Wilson talks about a Windows PowerShell Valentine’s Day special and the 14 things he loves about Windows PowerShell.

Microsoft Scripting Guy Ed Wilson is here. Well, it was several months ago when Microsoft Senior IT Pro Evangelist Blain Barton and I were talking. I said, you know we need to think about doing a holiday special. He said, "Valentines Day." I said, "Really?" He said, "Sure. Why not?"

Why not indeed. So over the next few weeks, we begin to think about a way to do it. We got Chis Caldwell involved and the idea began to take shape. A relationship show, where people call in and discuss matters of the heart. Of course, with certain types of people who are addicted to Windows PowerShell, those matters of the heart are windows PowerShell.

Cool, the idea is set. Now, who can we get to call in? Well, the list includes some of the most famous people in the community. People like Windows PowerShell MVP, Sean Kearney; Windows PowerShell MVP, Boe Prox; and Windows PowerShell MVP, Maximo Trinidad all called in with important questions. In addition, several people from Microsoft, such as Microsoft PFE, Ashley McGlone; Microsoft PFE, Brian Wilhite; and June Blender and Dave Bishop also called in. The show is fun, informative, and useful. The show closes out with a poem written by windows PowerShell MVP, Sean Kearney. You don’t want to miss it.

The result is TechNet Radio: IT Time – Valentines Day Special! The 14 things we LOVE about PowerShell.

image

PowerTip: Use PowerShell to Configure IP Address in Windows Server 2012 R2

$
0
0

Summary: Use the new cmdlets in Windows Server 2012 R2 to set up an IP address on a computer with one network adapter.

Hey, Scripting Guy! Question How can I use Windows PowerShell to configure an IP address in Windows Server 2012 R2?

Hey, Scripting Guy! Answer Use the Get-NetAdapter and Add-NewIPAddress cmdlets together.

   For the IP address of 10.0.0.5, with a gateway of 10.0.0.1, and 24 bits for the subnet mask (255.255.255.0):

$IPAddress=”10.0.0.5”

$Gateway=”10.0.0.1”

$Prefix=24

Get-NetAdapter | NEW-NetIPAddress -IPAddress $IPAddress -Defaultgateway $Gateway -Prefixlength $Prefix

String Formatting in Windows PowerShell

$
0
0

Summary: Learn about using formatted strings in Windows PowerShell.

Microsoft Scripting Guy, Ed Wilson, here. Today we have another guest blog by June Blender. To read more of June’s previous posts, see these Hey, Scripting Guy Blog posts. Now, here’s June…

I recently had the opportunity to help the Windows Azure and ASP.NET product teams with some Windows PowerShell automation. Although I was supposed to be the helper, I probably learned more from the interaction than anyone else. I learned about Windows Azure and the Windows Azure module for Windows PowerShell. And I learned a whole bunch about Windows PowerShell. I'm convinced that helping always benefits the helper. You always learn by interacting. This case was no exception.

One of the most fun things I learned was about string formatting.

When I saw the first drafts of the scripts, they had a lot of Write-Verbose calls like this one:

$VerbosePreference = "Continue"

$filepath = "C:\ps-test\test.txt"

$owner = "juneb"

$result = $true

Write-Verbose ("Created {0} by {1}. Result is {2}." –f $filepath, $owner, $result)

Here's the result:

VERBOSE: Created C:\ps-test\test.txt by juneb. Result is True.

This statement uses string formatting, that is, it creates a little template called a "format string" in the quoted string:

"Created {0} by {1}. Result is {2}."

The placeholders in the template are integers enclosed in curly braces. The integers must begin with 0 and increment by 1.

{0}, {1}, {2} ...

You can put the placeholders anywhere in the format string and use a placeholder multiple times in the same string.

To assign values to the placeholders, type -f (for format), and then type a comma-separated list of the values in the order that you want them to appear. The first value replaces the first placeholder {0} in the string, the second values replaces the {1}, and so on.

Any valid expression can be a value.

PS C:\> "Created {0} on {1} by {2}. Result is {3} times {4}." –f $filepath, [datetime]"1/12/2014", $owner, "Success", 14/7

Created C:\ps-test\test.txt on 1/12/2014 12:00:00 AM by juneb. Result is Success times 2.

You can use string formatting anywhere in Windows PowerShell where a string value is permitted. When you use a formatted string as the value of the Message parameter of Write-Verbose, you must enclose it in parentheses. Otherwise, Windows PowerShell tries to interpret -f as a parameter of Write-Verbose.

PS C:\ps-test> Write-Verbose -Message "{0}" -f "Hi" -Verbose

Write-Verbose : A parameter cannot be found that matches parameter name 'f'.

At line:1 char:30

+ Write-Verbose -Message "{0}" -f "Hi" -Verbose

+                              ~~

    + CategoryInfo          : InvalidArgument: (:) [Write-Verbose], ParameterBindingException

    + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.WriteVerboseCommand

PS C:\ps-test> Write-Verbose -Message ("{0}" -f "Hi") -Verbose

VERBOSE: Hi

The critical element here is the cool -f, which is the Windows PowerShell format operator. It's described briefly in about_Operators, but the real info is on the following sites:

These docs are really worth reading. Someone put a lot of time into them and wrote extensive and very useful remarks. I've had them bookmarked for years.

To use the -f operator, you put the format string (with placeholders) on the left of the -f and the values on the right:

<format string> -f <values>

"{0} is the {1}." - f  "ScriptingWife", "best"

String formatting is really familiar to people who code in languages that don't resolve expressions or variables that occur in strings. In these languages, you use a format string or you use the plus operator (+) to concatenate strings with expressions, like in this Python example:

>>> filepath = "C:\ps-test\file.txt"

>>> owner = "juneb"

>>> result = True

>>> 

>>> "Created " + filepath + " by " + owner + ". Result is " + str(result) + "."

'Created C:\\ps-test\file.txt by juneb. Result is True.'

Good luck getting the spaces right on the first try! Of course, you can do this in Windows PowerShell, too. Fortunately, it's not required.

PS C:\> $filepath = "C:\ps-test\file.txt"

PS C:\> $owner = "juneb"

PS C:\> $result = $True

PS C:\> "Created " + $filepath + " by " + $owner + ". Result is " + $result + "."

Created C:\ps-test\file.txt by juneb. Result is True.

String formatting, -f, and string concatenation with the plus operator (+) work in Windows PowerShell, but I always thought that they were only included to help people who are familiar with other languages work successfully in Windows PowerShell.

This is fun stuff, I thought. But, honestly, there's no need to do this in Windows PowerShell, because you can include expressions right in a double-quoted string.

   Note  Single-quoted strings are different. Windows PowerShell prints them as-is with no substitutions.

PS C:\> 'Created $filepath by $owner. Result is $result.'

Created $filepath by $owner. Result is $result.

PS C:\> "Created $filepath by $owner. Result is $result."

Created C:\ps-test\file.txt by juneb. Result is True.

/NOTE]

So, when I encountered formatted strings in the Windows Azure module scripts, I replaced them with the "PowerShell way" to do it. For example, I changed:

$VerbosePreference = "Continue"

$filepath = "C:\ps-test\test.txt"

$owner = "juneb"

$result = "Success"

Write-Verbose ("Created {0} by {1}. Result is {2}." –f $filepath, $owner, $result)

   To:

$VerbosePreference = "Continue"

$filepath = "C:\ps-test\test.txt"

$owner = "juneb"

$result = "Success"

Write-Verbose "Created $filepath by $owner. Result is $result."

And it worked perfectly. So, I went through the script replacing the formatted strings with double-quoted strings.

Then I came upon statements like these, which use properties and nested properties of objects.

PS C:\> $p = Get-Process PowerShell

PS C:\>Write-Verbose ("The {0} process uses the {1} window style." -f $p.Name, $p.StartInfo.WindowStyle)

These statements return:

VERBOSE: The powershell process uses the Normal window style.

But, when I changed this Write-Verbose message to use the variables in a double-quoted string, it didn't work:

PS C:\> $p = Get-Process PowerShell

PS C:\> Write-Verbose "The $p.Name process uses the $p.StartInfo.WindowStyle window style."

VERBOSE: The System.Diagnostics.Process (powershell).Name process uses the System.Diagnostics.Process (powershell).StartInfo.WindowStyle window style.

In formatted strings, any expression can be a value. That's not true in double-quoted strings. When the values are expressions, the value type replaces the variable in the double-quoted string.

You can wrap the variable properties in another variable by using parentheses or braces. For example, change:

$<name>

   To:

$($<name>)

   Or:

${$<name>}

So, $p.Name becomes $($p.Name) or ${$p.Name}.

PS C:\> Write-Verbose "The $($p.Name) process uses the $($p.StartInfo.WindowStyle) window style."

VERBOSE: The powershell process uses the Normal window style.

It works, but it's not pretty.

Another obvious solution is to evaluate the expressions and save the results in variables before using them in the double-quoted string.

PS C:\> $p = Get-Process PowerShell

PS C:\> $pName = $p.Name

PS C:\> $pStyle = $p.StartInfo.WindowStyle

PS C:\> Write-Verbose "The $pName process uses the $pStyle window style."

VERBOSE: The powershell process uses the Normal window style.

That works, of course, but it's not more efficient. And, more importantly, when you're writing scripts that you want people to read and interpret, it's not always clearer.

Instead, the original formatted string is efficient, and when you understand string substitution, much clearer.

PS C:\> $p = Get-Process PowerShell

PS C:\>Write-Verbose ("The {0} process uses the {1} window style." -f $p.Name, $p.StartInfo.WindowStyle)

The format string is also handy when creating strings that have a syntax that is different from the Windows PowerShell syntax. In this case, Windows PowerShell tries to interpret the variable that precedes the colon as a drive name:

PS C:\> $urlHost = $url.Host

PS C:\> $ValuesPort = $values.Port

Write-Verbose ("Add-AzureVM: The url is https:// $urlHost:$valuesPort/msdeploy.axd" -Verbose

At line:1 char:49

+ Write-Verbose "Add-AzureVM: Publish Url https://$urlHost:$valuesPort/msdeploy ...

+                                                 ~~~~~~~~~

Variable reference is not valid. ':' was not followed by a valid variable name character. Consider using ${} to delimit the name.

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

    + FullyQualifiedErrorId : InvalidVariableReferenceWithDrive

Any of the following statements work as expected without creating extra variables, but I think that the format string makes the intended syntax much clearer than the alternatives.

Write-Verbose ("Add-AzureVM: The url is https://{0}:{1}/msdeploy.axd" -f $url.Host, $Values.Port) -Verbose

Write-Verbose ("Add-AzureVM: The url is https://$($url.Host):$($Values.Port)/msdeploy.axd" -Verbose

Write-Verbose ("Add-AzureVM: The url is https://${$url.Host}:${$Values.Port}/msdeploy.axd" -Verbose

Write-Verbose ("Add-AzureVM: The url is https://" + $url.Host + ":" + $Values.Port + "/msdeploy.axd") -Verbose

So, when the message string includes simple variables, I use double-quoted strings. When the message string includes a property value that is used repeatedly, I save the property value in a new variable and use the variable a double-quoted string.

But when a string includes multiple expressions or an alternate syntax, I prefer a formatted string.

And I learned an important lesson about using formatted strings and the -f operator in Windows PowerShell. It's not just an interesting artifact. It's really useful.

~June

Thanks for writing this informative post, June!

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: Include Expressions in a String in PowerShell

$
0
0

Summary: Learn how to include expressions in a string in Windows PowerShell.

Hey, Scripting Guy! Question How do I include expressions in a string in Windows PowerShell? They're not replaced correctly in a
          double-quoted string:

PS C:\> $p = Get-Process PowerShell
PS C:\>"The $p.Name process uses the $p.StartInfo.WindowStyle window style."

The System.Diagnostics.Process (powershell).Name process uses the
System.Diagnostics.Process (powershell).StartInfo.WindowStyle window style.

Hey, Scripting Guy! Answer Enclose the values in a new variable:

PS C:\>"The $($p.Name) process uses the $($p.StartInfo.WindowStyle) window style."
The powershell process uses the Normal window style.

         Or use a formatted string:

PS C:\>"The {0} process uses the {1} window style." -f $p.Name, $p.StartInfo.WindowStyle
The powershell process uses the Normal window style.

Weekend Scripter: Use PowerShell to Start Hidden Process

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to start a hidden process.

Microsoft Scripting Guy, Ed Wilson, is here. This morning I decided to try something a bit different. I am having a cup of English Breakfast tea, but I added strawberry leaves, blackberry leaves, marshmallow root, and a cinnamon stick. It is a nice pot of tea. Very relaxing, and just thing to help start the day.

Using the Invoke-CimMethod cmdlet

One of the nice thing about using the CIM cmdlets, is that they work with Windows Management Instrumentation (WMI). They use standard WMI classes, and so the techniques work with other versions of Windows PowerShell and with other scripting languages. For example, two WMI classes that have been around forever are Win32_Process and Win32_ProcessStartInfo. I used both of these back in the VBScript days.

Note  The WMI Tasks: Processes page from MSDN shows how to accomplish this task via VBScript. The WMI team has begun to update some of these scenarios on the Windows Management Infrastructure BlogFor more information about using the Invoke-CimMethod cmdlet, see these Hey, Scripting Guy! Blog posts.

The basic syntax for the Invoke-CimMethod cmdlet is shown here:

  Cmdlet

  WMI class

  Method from class

  Arguments to method

  Invoke-CimMethod

  -ClassName

  -MethodName

  -Arguments

In the Start-Hidden function, the Invoke-CimMethod syntax becomes rather complex. First the easy parts:

Invoke-CimMethod -ClassName win32_process -MethodName create

Nice. Three of the four parts of the command are really easy. It is the –Arguments portion that is complex. Luckily, I have some help in adding the value for –Arguments. First, I know from looking at the Invoke-CimMethod help that –Arguments accepts a hash table. Second, I know what my three input parameters can be from looking at Create method of the Win32_Process class on MSDN. In addition, this site even has a nice VBScript script to provide some additional hints.

So then, my three input parameters are listed in the following table. It also lists the output parameter, which is the ProcessID.

  Direction

  Data type

  Argument Name

  [in]

  string

  CommandLine

  [in]

  string

  CurrentDirectory

  [in]

  Win32_ProcessStartup

  ProcessStartupInformation

  [out]

  uint32

  ProcessId

Based on this information, I create the following script for my –Arguments section.

 -Arguments @{

   commandline = $commandline;

   ProcessStartupInformation = New-CimInstance -CimClass (

     Get-CimClass Win32_ProcessStartup) -Property @{ShowWindow=0} -Local;

     CurrentDirectory = $null}

When I have script that works, I place the entire thing into a function, and try it out. In the command that follows, I load the function by running the script within the Windows PowerShell ISE. I then go to the immediate window and capture the returned method invocation object that contains the process ID and the error return script stored into the $rtn variable. I then use that object to check the process and to stop the process:

$rtn = Start-Hidden notepad.exe

Get-Process -id $rtn.ProcessId

Stop-Process -Id $rtn.ProcessId

The command and the output from the command are shown in the following image:

Image of command output

I uploaded the complete function to the Script Center Repository, and you can download it from this location: Start-Hidden function.

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: Start Hidden Process with PowerShell

$
0
0

Summary: Use a Windows PowerShell cmdlet to start a hidden process.

Hey, Scripting Guy! Question How can I launch a hidden process by using a Windows PowerShell cmdlet?

Hey, Scripting Guy! Answer Use the Start-Process cmdlet and specify a window style of hidden:

Start-Process -WindowStyle hidden -FilePath notepad.exe

2014 Winter PowerShell Scripting Games Wrap Up #1

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, shares what he noticed while grading the 2014 Winter PowerShell Scripting Games entries.

Image of logo

Microsoft Scripting Guy, Ed Wilson, is here. So the 2014 Winter PowerShell Scripting Games are over. One of the cool things about this year’s Winter Games is that they were team events. This means that groups formed and tackled some pretty difficult scenarios as a team. This also means that the quality of the submissions was extremely high. I thought it would be interesting to go over some of the things I noticed while grading the submissions this year.

Use of aliases

I have written quite a bit about aliases in scripts. Here are some of the posts related to aliases:

Readability vs. speed of entry

Don’t get me wrong, Windows PowerShell aliases are extremely useful, and they make working interactively from the Windows PowerShell console fast. The thing is that this fast aspect tends to be a tradeoff for readability.

When using the Windows PowerShell ISE and when writing a script, Tab expansion and IntelliSense offer improvements that can make quick work out of the task of typing extremely long cmdlet names. In fact, this tool of Tab expansion and IntelliSense is one of the reasons that we can have long, descriptive cmdlet names.

It is a strength of Windows PowerShell that I can read the script and pretty much understand what it is doing—even if I am unfamiliar with the module or the technology. For example, someone someday may write a cmdlet named Invoke-VirusScan. Without having seen the cmdlet or having read any help, I can imagine that the cmdlet will kick off a virus scan.

I would also imagine that there should be parameters for which disk to scan, or an –all switched parameter, and even a –skip parameter so that I can choose to not scan certain file types and folders. But, on the other hand, if I see an alias called ivs, I have no idea what the command does.

Confusion abounds

There are many aliases that look like other things, for example: Kill, Dir, Where, and Sort. For example, Sort is also the name of an executable in CMD. This is shown in the image that follows:

Image of command output

When the cmdlet , Sort-Object, does not behave like Sort.exe, the person attempting to write the script becomes confused and wonders why it does not work. This is also true of Dir, Kill, and others. The fact that I can start CMD inside of Windows PowerShell, as shown in the previous image, means a whole lot of confusion.

In fact, one alias, Foreach for the Foreach-Object cmdlet is also the name of a Windows PowerShell keyword, Foreach. These two identical looking commands behave completely differently, and this causes a serious stumbling block for beginners—and even for some intermediate scripters.

So, the best thing to do in a script is to avoid using aliases. It is easy enough to do. You can use my Remove-AliasFromScript function that is part of my Windows PowerShell ISE profile and modules, or you can simply use Tab expansion to complete the cmdlet names. The advantage is that not only do you get ease of entry, but you also get correct spelling and cases.

Formatting Windows PowerShell script

At the beginning of the chapter on debugging in my book, Windows PowerShell Best Practices, I mention that if you can read and understand your script, you will eliminate nearly 90 percent of all mistakes that eventually lead to a debugging situation. I am firmly convinced that this statement is true. You can also contribute to that percentage by developing good, sound development techniques.

One of the things that contributes to reading Windows PowerShell script is how it is formatted. There are two extremes that should be avoided:

  • Avoid one-liner syndrome in a script
  • Watch for too much tabbing

Avoid one-liner syndrome in a script

When working interactively at the Windows PowerShell console, I love one-liners. Those pithy one-line commands that seem to accomplish great things. The fact that it may wrap for several lines inside the Windows PowerShell console does not deter usefulness, but it does impair reusability and debugging in the event that the one-liner does not work. But, hey, that is the Windows PowerShell console.

I really avoid this inside the Windows PowerShell ISE. The Windows PowerShell ISE can be used to run interactive commands, but I like to use it as a way to break down the script and make it easier to read—even if it is a logical one-line command.

Following is an example of what I am talking about. When I run the script that is shown in image of the Windows PowerShell ISE, nothing happens. No error generates, nothing appears.

Image of command output

I have to scroll over to look at the remainder of the command. But when I do that, I still cannot see the entire command, so it makes troubleshooting a major pain. Here is the scrolled over portion of the script:

Image of command output

It is obvious now why nothing appears to happen. I am starting a process, then getting the process, and then stopping the process—all in the same one-liner.

One of the best ways to fix this issue is to separate the script at the pipeline character and at the semicolon. In fact, I do not even need the semicolon now that I have things broken out onto individual lines.

Image of command output

Watch for too much tabbing

The opposite extreme is too much tabbing. It results in exactly the same type of situation. The script becomes hard to read, as shown in the following image:

Image of command output

The solution, once again, is to tighten up the script. It is OK to indent and to align, but not if it comes at the expense of readability. Instead of using a full tab, I often only use a single or at times a double space for my indentions. I find that it makes my script easier to read, and therefore, easier to debug if it ever comes to that.

2014 Winter Scripting Games Wrap-Up Week will continue tomorrow.

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: Is It a PowerShell Alias?

$
0
0

Summary: Quickly find multiple Windows PowerShell aliases.

Hey, Scripting Guy! Question I have a bunch of Windows PowerShell commands I have been using, but they seem to act strangely sometimes.
          I need to know if they are aliases or real commands. How can I tell?

Hey, Scripting Guy! Answer Use the Get-Alias cmdlet to look up aliases and resolve them to Windows PowerShell cmdlet names.
          You can do this in a single command because the –Name parameter accepts an array of aliases, for example:

Get-Alias -Name sort, select, foreach, where, dir, cls

2014 Winter PowerShell Scripting Games Wrap Up #2

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, shares what he noticed while grading the 2014 Winter PowerShell Scripting Games entries.

Image of logo

Microsoft Scripting Guy, Ed Wilson, is here. This morning things are a bit chilly around here. I am sipping a nice Assam Blatt tea that I got when I was in Hamburg on our last trip. I added a bit of local honey, a lemon, and a cinnamon stick to the pot. And it is quite refreshing and warming.

This is the second post in a series in which I talk about things I noticed whilst grading submissions for the 2014 Winter Scripting Games. You might want to read 2014 Winter PowerShell Scripting Games Wrap Up #1. I talked about best practices for using aliases and for formatting of Windows PowerShell scripts.

The need for structured error handling

Note  There are a couple of really good Hey, Scripting Guy! Blog posts about structured error handling. You may want to start with How Can I Use Try/Catch/Finally in Windows PowerShell? Then read a guest post by Bhargav Shukla called PowerShell Error Handling and Why You Should Care. The two posts together provide a nice foundation for this technique.

Handling errors in production scripts is a good thing. For example, consider the following pseudo-code, which one may need to do when consolidating directories and attempting to clean up storage:

Step 1: Create a folder named folderA.

Step 2: Copy the content of a folder named folderB to folderA.

Step 3: Delete folderB and all its content.

Now, suppose that creating the new folderA fails, as does the copy operation of folderB to folderA. But the last step (Delete FolderB) succeeds. Obviously, this is not the optimal solution. Therefore, some sort of error handling needs to be added. One way to do this is to add a couple of checks to the script. Here I revise the pseudo-code to include two error checks:

Step 1: Create a folder named folderA.

Step 2: Check that folderA created successfully.

Step 3: Copy the content of a folder named folderB to folderA.

Step 4: Check that the content of folderB copy successfully to folderA.

Step 5: Delete folderB and all its content.

By checking for the successful creation of folderA and for the successful copying of folderB to folderA, I can help to avoid disaster. If it is important, I might also want to check that folderB and its content is also successfully deleted.

Using a series of if type statements

One of the most rudimentary types of construction to be created is one I see quite a bit: using if to check on stuff and else to decide what to do. An example of this is shown here:

$folder = "c:\myfolder"

If(-not (Test-Path -Path $folder))

  {

    Write-host "$folder was not available"

    $rtn = Read-host -Prompt "Do you want to create $folder? Y/N"

      If ($rtn -match "y")

            { MD $folder }

      ELSE {

            Write-Host "exiting now because $folder does not exist and you don't want to create it"}}

 ELSE {

        Write-Host "Writing to $folder now" }

This script first test’s to see if the folder exists. If it does not, it prompts to create and then creates the folder. Otherwise, it states that it will exit, or that it will write to the folder. It works, but is a lot of work—and truthfully, is a bit cumbersome to read.

Using Try/Catch/Finally

A better approach, than a series of if/elseif/else statements is to use Try/Catch/Finally. One thing to keep in mind when using Try/Catch/Finally is that not having a folder in existence is not a terminating error. By default, Windows PowerShell will try to go to the next line of the script.

To make the Catch portion actually catch the non-terminating error, I need to change the $ErrorActionPreference variable from Continue (the default value) to Stop. This will halt the script execution on an error, and enable the Catch portion to catch.

I consider it a best practice to set the $ErrorActionPreference back to Continue when I am done with this portion of the script. In a more complete solution, I would actually query for the current value of $ErrorActionPreference, store it in a variable, and use that to set it back (assuming that it needs to change).

The reason I am catching a [system.Exception] instead of a “Directory not found” or a “File not found” error, is because for some reason, the error that reports back is “Access is denied”—even though the directory does not exist. So a [System.Exception] is any kind of exception, and it will catch “Access is denied,” “File not found,” or “There are too many sun flares today.”

In the image that follows, I run the Copy-Item line of script, and it generates an access denied error.

Image of command output

When I run the entire script, nothing appears. This is because the Catch block catches the exception; and in the Catch script block, I create the folder, and then copy the file to the folder. This is shown in the following image:

Image of command output

The complete Try/Catch/Finally sample is shown here:

# -----------------------------------------------------------------------------

$myfile = "C:\fso\music.csv"

$folder = "c:\myfolder"

 

Try {

 $ErrorActionPreference = "Stop"

 Copy-Item -Path $myfile -Destination $folder -Force }

CATCH [System.Exception]{

 MD $folder | Out-Null

 Copy-Item -Path $myfile -Destination $folder -Force }

FINALLY { $ErrorActionPreference = "Continue" }

2014 Winter Scripting Games Wrap-Up Week will continue tomorrow.

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 Errors

$
0
0

Summary:  Use Windows PowerShell to find information about Windows PowerShell errors.

Hey, Scripting Guy! Question How can I find more information about a specific error when I look at the $error automatic variable?

Hey, Scripting Guy! Answer The $error automatic variable contain rich objects. For example, the InvocationInfo property shows
          what code was called that generated the error.
          The following illustrates how to find the most recent error (error 0):

$Error[0].InvocationInfo

Note  Tab expansion works for this.

2014 Winter PowerShell Scripting Games Wrap Up #3

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using standard folders in his review of the 2014 Winter Windows PowerShell Scripting Games.

Microsoft Scripting Guy, Ed Wilson, is here. It is beginning to look like spring here in Charlotte, North Carolina. This is a welcome relief, because just a couple of weeks ago, it was like snow city. Schools closed. Businesses closed. The governor of South Carolina declared the state a disaster area and mobilized the National Guard, so it has been rather exciting around here recently. But nothing compares with the excitement of my new Surface 2 Pro that the Scripting Wife bought me. I mean, wow!

Note  FTC Publishes Final Guides Governing Endorsements, Testimonials. The Microsoft Scripting Guys work for the Microsoft Corporation. The Microsoft Corporation provides me with a salary, health insurance, bonus, U.S. national holidays off, and annual leave. The Microsoft Corporation, however, has not provided me with a Surface 2 Pro. The Scripting Wife works for herself, and it is she who bought the new Surface 2 Pro with her own money. She was not coerced, intimidated, or otherwise influenced. She received no monetary considerations from any outside party. She bought it simply because she wanted to do something nice, and because she knows that the Surface 2 Pro absolutely rocks!

Nearly as exciting as having a new Surface 2 Pro to play with has been grading the 2014 Winter Scripting Games. As for winter, see the earlier paragraph —it fits. The team concept for the Games this year resulted in some excellent submissions. All of the scripts have been worthy and worthwhile submissions. Please keep my critiques in the spirit in which they are intended—mainly, they are simply some ideas that may be worthwhile to investigate.

Image of logo

     Note  This is the third in a series of blog posts in which I talk about things I noticed whilst grading submissions for the
     2014 Winter Scripting Games. In case you missed the previous episodes:

Today’s post talks about using standard Windows folders from within Windows PowerShell scripts.

The need for folders

Often a script will need to write some sort of output to a file. Where I write this output can become a major design decision. There are several considerations that need to be made:

  • Am I the only person who needs to access the file?
  • Do others need to access the file?
  • Will the file need to be accessed across the network?
  • Will I have rights to the file?
  • Does the folder that will contain the file exist, or does it need to be created?

If more than one user must access the file, the file needs to be stored in a shared folder, or at least a folder in which more than one user has permission to access. If a file must be accessible across the network, the file needs to be stored in a shared folder of some sort. The folder can be a local folder that is shared with the user group that needs access to the file, or it can be stored in a folder that is located on a network share.

A concern about storing a file on a network share, is that depending on the size of the data, you do not want to write directly to the file on the network share. Instead what you want to do is to write to the file locally, and then copy it to a network share.

Also remember the security model. Usually, non-elevated users do not have access to files that are stored in a root folder. Because folders inherit permissions, if you create a folder directly off the root, by default non-elevated users will not have access to that folder either. This means that you need to modify access rights to a folder if you create it immediately off the root. When you create a folder manually, this is not normally an issue (because you are there, and you remember to check the access rights). But when you create a folder via a script, it can become an issue that you were not expecting to deal with.

Using special folders can be a nice solution to security, presence, and access issues. This is because the special folders are part of a user’s profile, and the folders already have the appropriate access rights in place. The trick, of course, is knowing where to find them.

Special folders have been around forever, it seems. And just as long, scripting tools have provided ways to access the special folders. There are four main ways to access these folders:

  • Use the GetSpecialFolder method from the Scripting.FileSystemObject object
  • Use the SpecialFolders property from the Wscript.Shell object
  • Use the NameSpace method from the Shell.Application object
  • Use the GetFolderPath static method from the System.Environment .NET Framework class

Finding special folders

Environment.SpecialFolder Enumeration is documented on MSDN. Unfortunately, what is not documented is how to actually use it in Windows PowerShell. This is because the enumeration does not behave like a standard enumeration. The site is useful, however, because it describes each of the folder names, and their use in Windows.

     Note  I have written quite a bit about working with special folders via Windows PowerShell.

Special folders in the Windows world are useful because as a scripter I can be assured that they exist and that I will have permissions to access them. A separate subject is that of using a temporary file. It is easy to create a temporary file in the temporary folder.

Of course, I also consider it a best practice to delete temporary files after my script completes. I really consider it poor programing practice to leave temporary files lying around in the temporary folder. One reason that the temporary folder fills up with files is because it is so easy to add stuff to it. For a good approach to working with temporary files in temporary directories, see How Can I Create, Display, and Then Delete a Temporary Text File?

Working with the Environment class

Perhaps, one of the best ways to work with special folders, is to interact with the System.Environment .NET Framework class. To do this, I need to learn how to use the Environment.SpecialFolders enumeration. For whatever reason, it does not work the way I would expect it to work. In fact, it looks a little strange. I need to use [Environment+SpecialFolder] to work with the enumeration. To start with, I can pipe the type to the Get-Member cmdlet and look at the Static properties. The command is shown here:

[environment+SpecialFolder] | Get-Member -Static -MemberType property

The command and associated output look like this:

Image of command output

A better output of the special folder enumeration is obtainable via the [enum] .NET Framework class. The command to do that is shown here:

[enum]::GetValues([environment+SpecialFolder])

The command and output are shown in the following image:

Image of command output

Using the enumeration values

When I know how to find the enumeration values, the next thing I need to do is find the path to the special folder. To do this, I use the [environment] .NET Framework class, and I use the static GetFolderPath method. I then plug-in one of the values that I obtained by looking at the enumeration, or that I found on MSDN. For example, to get the path to my desktop, I use the following command:

[environment]::GetFolderPath("Desktop")

I can use this in script. For example, if I want to write a list of processes to a text file, and have that file appear on my desktop, all I need to do is:

  • Get the path to the special folder
  • Append the name of the file to complete the path
  • Use any of the normal Windows PowerShell techniques to create the file and add data to the file

Although I can use this technique interactively from the Windows PowerShell console, I normally would not do this. To be frank, it is a bit of work. If, on the other hand, I wanted to write to files on my desktop all the time, I would entertain the idea of creating a global Windows PowerShell variable in my Windows PowerShell profile, and store the path to the desktop there. It might make a useful addition.

So here is how I use the special folder. First I get the path to the folder:

[environment]::GetFolderPath("Desktop")

Now, I append a name of a file to the path. To do this, I use the Join-Path cmdlet. Note that I must use a subexpression in my Join-Path cmdlet to force the creation of the path to the desktop first:

$desktop = Join-Path -Path $([environment]::GetFolderPath("Desktop")) -child proc.txt

Now, I get my process information and write it to a text file as shown here:

Get-Process | Select name, id | Out-File $desktop -Encoding ascii

2014 Winter PowerShell Scripting Games Wrap-Up Week continues tomorrow when I will talk about using Write-Verbose and Write-Error from within a Windows PowerShell script.

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 User Profile Path

$
0
0

Summary: Use Windows PowerShell to find the user profile path.

Hey, Scripting Guy! Question How can I easily get information about the folder and path to the profile for a currently signed-in user?

Hey, Scripting Guy! Answer Use the Env: PowerShell drive, and select the UserProfile environmental variable:

$env:USERPROFILE

2014 Winter PowerShell Scripting Games Wrap Up #4

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, continues his Scripting Games 2014 wrap up with a discussion of error and verbose message streams.

Microsoft Scripting Guy, Ed Wilson, is here. Things are starting to settle down here in the scripting household. Windows PowerShell Saturday #007 was a rousing success in Charlotte, North Carolina. Valentine’s Day was cool and a special treat for the Scripting Wife and I, and the 2014 Winter Scripting Games have concluded. So what’s to do? Well, today I am sipping a nice cup of Charleston Breakfast tea. I added peppermint, spearmint, honey, fresh lemon, and a cinnamon stick to the mixture. It is quite refreshing. Charleston Breakfast tea is one of the teas that is grown at the Charleston Tea Plantation. It has a nice robust flavor when steeped for four minutes in 208 degree water.

Image of logo

     Note  This is the fourth in a series of blog posts in which I talk about things I noticed whilst grading submissions for the
     2014 Winter Scripting Games. In case you missed the previous episodes:

In today’s post, I’ll talk about using the Write-Verbose and Write-Error streams in Windows PowerShell scripts.

Alternative output message streams

One of the things I saw while grading scripts for the 2014 Winter Scripting Games was people creating their own alternate message streams. For example, they might do something like the following:

If($verbose) {Write-Host "This is verbose output"}

ELSE {Write-Host "This is normal output"}

Although this sort of thing might actually work (at least to an extent), it is not optimal. In fact, it causes a lot of extra work. This is because Windows PowerShell already has several message streams including:

  • Normal output
  • Errors
  • Warnings
  • Verbose output
  • Debug messages

Whether these messages display anything is due to the configuration of one of the following Preference variables:

  • DebugPreference
  • ErrorActionPreference
  • VerbosePreference
  • WarningPreference

The neat thing is that I implement my script in the proper Windows PowerShell fashion, then I can capture these alternate message streams in a text file via the redirection operators introduced in Windows PowerShell 3.0. The following table lists the redirection operators.

Note  The 2>, 2>>, and 2&1 operators existed in Windows PowerShell 1.0.

Operator

 Description

 Example

  >

 Sends output to the specified file

 Get-Process > Process.txt

  >>

 Appends the output to the contents of the specified file

 dir *.ps1 >> Scripts.txt

  2>

 Sends errors to the specified file

 Get-Process none 2> Errors.txt

  2>>

 Appends errors to the contents of the specified file

 Get-Process none 2>> Save-Errors.txt

  2>&1

 Sends errors (2) and success output (1) to the success output stream

 Get-Process none, Powershell 2>&1

  3>

 Sends warnings to the specified file

 Write-Warning "Test!" 3> Warnings.txt

  3>>

 Appends warnings to the contents of the specified file

Write-Warning "Test!" 3>> Save-Warnings.txt

  3>&1

 Sends warnings (3) and success output (1) to the success output stream

Function Test-Warning

{Get-Process PowerShell;

Write-Warning "Test!" }

Test-Warning 3>&1

  4>

 Sends verbose output to the specified file

Import-Module * -Verbose 4> Verbose.txt

  4>>

 Appends verbose output to the contents of the specified file

Import-Module * -Verbose 4>> Save-Verbose.txt

  4>&1

 Sends verbose output (4) and success output (1) to the success output stream

Import-Module * -Verbose 4>&1

  5>

 Sends debug messages to the specified file

 Write-Debug "Starting" 5> Debug.txt

  5>>

 Appends debug messages to the contents of the specified file

 Write-Debug "Saving" 5>> Save-Debug.txt

  5>&1

 Sends debug messages (5) and success output (1) to the success output stream

Function Test-Debug

{ Get-Process PowerShell;

Write-Debug "PS" }

Test-Debug 5>&1

  *>

 Sends all output types to the specified file

 Function Test-Output

{ Get-Process PowerShell, none;

Write-Warning "Test!";

Write-Verbose "Test Verbose";

Write-Debug "test debug"} ;

Test-Output *> Test-Output.txt

  *>>

 Appends all output types to the contents of the specified file

 Test-Output *>> Test-Output.txt

  *>&1

 Sends all output types (*) to the success output stream

 Test-Output *>&1

An example of how to use the alternate message streams is shown here:

$desktopPath = [System.Environment]::GetFolderPath("Desktop")

Function Out-VerboseStream

{

 BEGIN { $oldVerbosePreference = $VerbosePreference }

 PROCESS {

 $VerbosePreference = "Continue"

  Write-Verbose "This is verbose output"

  "This is regular output" }

END {$VerbosePreference = $oldVerbosePreference }

}

The key features are to set the preference variable to “Continue” to permit it to output. As a best practice, you should set it back when you are finished. As shown in the following image, I first run the function, and the verbose stream and the regular stream appear in the output pane.

Image of command output

I now use the redirection operator to redirect the verbose stream output to a text file:

Image of command output

Now when I use the redirection operator to redirect the verbose stream, it goes in a text file.

The following table illustrates the different type of redirection characters that are used to represent the message streams.

  Character

  Meaning

  * 

   All output

  1 

   Success output

  2 

   Errors

  3 

   Warning messages

  4 

   Verbose output

  5 

   Debug messages

That is all there is to using different output streams. 2014 Winter PowerShell Scripting Games Wrap-Up Week continues tomorrow when I will talk about using the Switch statement.

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 Status of PowerShell Preference Variables

$
0
0

Summary:  Easily find the status of Windows PowerShell Preference variables.

Hey, Scripting Guy! Question How can I see the preference settings that I can change with Windows PowerShell?

Hey, Scripting Guy! Answer Look at variables that contain the word Preference  in their name by using the Get-ChildItem 
          and looking at the Variable drive:

Get-ChildItem variable:*preference

Note  To see all of the Windows PowerShell Preference variables, see about_Preference_Variables.
Many of the Preference variables are not present on the Variable drive unless you change their initial values.


2014 Winter PowerShell Scripting Games Wrap Up #5

$
0
0

Summary: Microsoft Scripting guy, Ed Wilson, talks about using the Windows PowerShell Switch statement to clean up script in a wrap up of the 2014 Winter Scripting Games.

Microsoft Scripting Guy, Ed Wilson, is here. The Scripting Wife and I have been busy planning our trip to Houston for the 2014 North American TechEd Conference. The Scripting Guys will have a booth on the conference floor, and the Scripting Wife and I will be there along with Marc Adam Carter and Jaap Brasser. This is a really cool team, and you will want to stop by and chat about Windows PowerShell. The Scripting Wife will be putting out our booth schedule as we get closer to the event. For now, stay tuned.

     Note  This is the fifth in a series of blog posts in which I talk about things I noticed whilst grading submissions for the
     2014 Winter Scripting Games. In case you missed the previous episodes:

If If IF / else Else ELSE

For the record, there is nothing wrong with doing if if if / else else else in a Windows PowerShell script. In fact, it is fast, and it is what Windows PowerShell really does behind the scenes anyway. So what is the big deal about Switch? Well, it simplifies the script, makes it easier to read, and it is less cluttered.

In the following function, I create a sample if/elseif/else structure to evaluate the value passed to the function:

Function Example-If

{

 Param ($a)

  If ($a -eq 0) { "0 is the number" }

    ElseIf ($a -eq 1) {"1 is the number" }

    ElseIf ($a -eq 2) {"2 is the number"}

    Elseif ($a -eq 3) {"3 is the number"}

  Else {"Not sure what the value of `$a really is"}

}

Although there is nothing wrong with the script, it was a decent amount of writing to do, and it is also a bit cumbersome to read. Not only that, it is a bit error prone due to the constant repetition. When I run the script, the output that is shown in the following image appears.

Image of command output

To use the Switch statement, I begin with the word Switch. Next I include the condition that I will evaluate, followed by a script block that defines each potential value and what I will do when the condition comes True. Following is an example of using the Switch statement:

Function Example-Switch

{

 Param($a)

 Switch ($a)

  {

    0 {"0 is the number"}

    1 {"1 is the number"}

    2 {"2 is the number"}

    3 {"3 is the number"}

    Default {"Not sure what the number is"}

   }

The image that follows is an example of using the Example-Switch function and the output associated with the function.

Image of command output

If you do not remember the syntax for the Switch statement, it is easy enough to use the built-in snippets from the Windows PowerShell ISE to add-in a framework of script. This is shown in the image that follows.

Image of menu

All I need to do to get to the script snippets in the Windows PowerShell ISE is to click Edit, and then click Start Snippets, or I can press Ctrl plus J to bring up the snippet dialog box. I can then use the Down arrow to move through the collected snippets until I arrive at the Switch snippet. If I hover long enough, then IntelliSense will pop up a box that shows what the script snippet looks like. For more details, see the Hey, Scripting Guy! Blog post by Windows PowerShell MVP, Jonathan Medd, Using PowerShell ISE Snippets to Remember Tricky Syntax.

That is all there is to using the Windows PowerShell Switch statement to clean up your script. The 2014 Winter Scripting Games Wrap-Up Week continues 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: Personalize Your Copy of PowerShell

$
0
0

Summary: Easily add your user name to your Windows PowerShell console window.

Hey, Scripting Guy! Question I often start multiple Windows PowerShell consoles with different credentials.
          To avoid getting confused, how can I change the window title to my user name?

Hey, Scripting Guy! Answer Use the $host automatic variable, and change the WindowTitle property to the user name:

$host.ui.RawUI.WindowTitle = $env:USERNAME

2014 Winter PowerShell Scripting Games Wrap Up #6

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, wraps up the 2014 Winter Scripting Games and talks about parameter validation.

Weekend Scripter: Parameter Validation

Microsoft Scripting Guy, Ed Wilson, is here. Today, I'm playing with my new Surface Pro 2 device. It came with a year of free Skype and two years of 200 GB storage on OneDrive. WooHoo! It is great. I love that the Surface Pro 2 is so fast and so robust. I was really surprised and happy when the Scripting Wife got it for me. Cool.

Image of logo

     Note  This is the final post in a series in which I talk about things I noticed whilst grading submissions for the
     2014 Winter Scripting Games. In case you missed the previous episodes:

In today’s post, I’ll discuss adding robustness to Windows PowerShell scripts by using parameter validation.

What are parameter validation attributes?

Glenn Sizemore wrote a great introduction to Windows PowerShell parameter validation attributes in his blog post, Simplify Your PowerShell Script with Parameter Validation. It is a good overview. I also talked about using a ValidatePattern parameter attribute in Validate PowerShell Parameters before Running the Script. That post provides a good example of using a regular expression pattern to validate parameter input.

The whole point of using parameter validation attributes is that it does the following:

  • Simplifies Windows PowerShell scripting by using built-in capabilities
  • Makes your Windows PowerShell script easier to read and easier to understand
  • Makes the script more robust by checking permitted input values
  • Simplifies script error handling

About parameter validation attributes

There are a number of parameter validation attributes. They are documented in about_Functions_Advanced_Parameters in the TechNet Library. The following table lists the parameter validation attributes.

Validation Attribute

Meaning

AllowNull

Permits a null value for a Mandatory parameter

AllowEmptyString

Permits an empty string, “”, as a value for a mandatory parameter

AllowEmptyCollection

Permits an empty collection, @() for the value of a mandatory parameter

ValidateCount

Specifies the minimum and the maximum values that a parameter accepts

ValidateLength

Specifies the minimum and the maximum number of characters in a value supplied to a parameter

ValidatePattern

Specifies a regular expression pattern a value must match

ValidateRange

Specifies a range of values for a parameter value

ValidateScript

Code raises an error if code evaluates to “false”

ValidateSet

Specifies that the value for a parameter must be a member of the defined set

ValidateNotNull

Generates an error if the value is null

ValidateNotNullOrEmpty

Generates an error if the parameter value is used in a function call and is null, an empty string or an empty array

 

A practical example

In the following function, the input must be a member of a particular set. The set is defined in a variable called $myset and an if/else construction checks input to see if it is a member of that set. If it is, the input is valid. If it is not, an error message appears, and the permissible values are displayed. This is a useful script, and it is a nice check on the input values.

Function My-Parameters

{

 Param ($myinput)

 $myset = "red","blue","green","orange"

 if($myset -contains $myinput)

    {Write-Output "The input is valid"}

 else

    { throw "The input is not valid. It must be a member of $myset" }

}

After I load the function, I call the function and pass a couple values. The values are members of the $myset set, and therefore, it is valid input. When I pass the value almond, however, an error is thrown. This is shown in the image that follows:

Image of command output

I can rewrite the previous script to use parameter validation. To do this, I use the [ValidateSet()] attribute:

Function Use-ParameterSetValidation

{

  Param(

   [ValidateSet("red","blue","green","orange")]

   [string]$myInput)

   Write-Output "The input is valid"

}

Not only is the script a lot cleaner, but it is much less typing. In addition, the script is easier to read because I do not need to weave through the if/else statement and the throw statement. But more than that, if I run the function in the Windows PowerShell ISE, I also gain IntelliSense. In this way, it makes it very difficult to choose the wrong value. In fact, I have to deliberately ignore the IntelliSense to enter a false value. The following image illustrates the free IntelliSense I gain when I implement the ValidateSet parameter attribute.

Image of command output

Even though I did not wire up a throw statement, if I ignore the IntelliSense and I supply the wrong value for the parameter, an error occurs. In addition, like in my previous example where I displayed the contents of the $myset variable to show the permissible values, Windows PowerShell supplies the permissible values for the set. This is shown in the following image:

Image of command output

Join me tomorrow when I begin a series about using Windows PowerShell with Microsoft Surface RT, Microsoft Surface Pro, and Microsoft Surface Pro 2. It will be some fun 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: Get the Latest PowerShell Help

$
0
0

Summary: Learn how to get the latest Windows PowerShell Help online.

Hey, Scripting Guy! Question I do not have Admin rights so I cannot update my local Windows PowerShell Help.
          How can I access the latest updated Help online?

Hey, Scripting Guy! Answer Use the –online switched parameter with the Get-Help cmdlet:

get-help Get-Process -Online

Weekend Scripter: Pin PowerShell Script to Start Screen

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about pinning a Windows PowerShell script to the Windows 8.1 Start screen.

Microsoft Scripting Guy, Ed Wilson, is here. The other day, the Scripting Wife and I had a couple of neighbors over for dinner. While munching on snacks, he said that he had recently upgraded his laptop from Windows 7 to Windows 8. His initial impression was that Windows 7 was for work, but Windows 8 was for play, and he needs to use his laptop to accomplish work. He said, “Everything is at least five or six clicks away.”

I told him he was trying too hard, and I took him to my office to give a short demonstration. With my multiple monitor configuration, I have the Windows 8.1 Start screen on one monitor, my Word documents on another monitor, and the Windows PowerShell ISE on the third monitor. It makes life really easy. I love the Start screen because everything is a single click away, not five or six clicks. The trick is to know how to configure your Start screen, and how to add or take away what you want to use.

It’s about battery status

I have a Surface 2 Pro and a Surface RT that take turns following me around the house like little puppy dogs. They are great and helpful, and I do not know how I ever got along without them. But this usefulness comes at a price. There is no device that will run for 18 continuous hours of operation. Therefore, I have two devices, and I swap them out.

I, of course, use the Surface 2 Pro for things that I need it for, such as using Live Writer to write blog posts, or to upload pictures from my camera into my image editing software program. Yep, it is a great device, but I need to watch my battery life. I can swipe from the right side of the screen, click Properties, and get a battery status. This is shown in the image that follows:

Image of status

The icon looks full, but is it really 100% topped off? Or is it 89% left? When exactly, does the icon change?

PowerShell and CIM give me the information

I can easily find out how much juice is left by using Windows PowerShell. All I need to do is to use the Get-CimInstance cmdlet and return information from Win32_Battery. Because I only want the information, I use the GCIM alias as shown here:

gcim win32_battery

The output is shown in the following image:

Image of command output

The output is clear. I have 97% of my battery time left, and an estimated running time of 189 minutes. Cool. I should be able to finish my blog post before the battery goes on holiday. The command is easy enough to type, and I have been doing it consistently for over a year. I absolutely love that I can use Windows PowerShell on the Surface.

But, it is still a decent amount work to open the Windows PowerShell console and type my command simply to see the output. Wouldn’t it be easier if I could combine my love of the Start screen and my love of Windows PowerShell? Well, as it turns out I can.

I decided to create a shortcut to my Windows PowerShell script, in which I use the arguments of the PowerShell.exe command to retrieve my battery-life information. I place the shortcut in the Programs special folder, and I create a .lnk file as shown here:

Function New-Shortcut

{

 Param($scriptFile = "c:\fso\get-battery.ps1",

       $Description = "Created by script",

       $WorkingDirectory = "C:\")

 $arguments = " -noexit -file $scriptFile -ExecutionPolicy bypass"

 $program = "PowerShell.exe"

 $linkname = Split-Path -Leaf -Path $scriptFile

 $startPage = $wshShell.SpecialFolders.Item("Programs")

 $shortcut = $wshShell.CreateShortcut("$startPage\$linkname.lnk")

 $Shortcut.TargetPath = $program

 $Shortcut.description = $description

 $ShortCut.arguments = $arguments

 $shortcut.IconLocation= $program

 $shortcut.WorkingDirectory = $workingdirectory

 $Shortcut.Save()

}

For my purposes, all I need to do is to change the location of the script that I want a shortcut to. My Get-Battery.ps1 script? Well, it is shown here:

Image of script

There is no script editor on the Surface RT, but that does not stop me from creating scripts by using Notepad. In fact, I used Notepad for years to write scripts before Windows PowerShell 2.0 came out with an editor. All I need to do is to save the script file, and then I can use my previous function to store a shortcut to the script within the Programs special folder.

The arguments that I specified for PowerShell.exe include –noexit. I do this so I can see the output from the script. It is sort of the point of the exercise. I also specify the path to the file, and I specify an –executionpolicy of bypass. In this way, I do not need to worry about the script execution policy on my device. When I run the function, the shortcut is placed in the Programs special folder.

Now, I need to restart my device, so that the Start screen will reload. When this is complete, I can use Windows PowerShell to find the script, as shown here:

PS C:\Users\ed> Get-StartApps | ? name -like 'g*'

 

Name                                         AppID

----                                         -----

get-battery.ps1                              Microsoft.AutoGenerated.{B2CC9256-3AF2-2A...

Games                                        Microsoft.XboxLIVEGames_8wekyb3d8bbwe!Mic...

Notice that the shortcut to my script, is autogenerated. Cool stuff.

Where else can I find my shortcut? It is in the Apps location as shown here:

Image of menu

Now, all I need to do is to right-click the shortcut on the App page, and click Pin to Start. This is shown here.

Image of menu

After I do that, it shows up on my Start screen, and I can put the shortcut anywhere I want it. Here, I have moved it to a handy location—directly under my games.

Image of screen

When I click the shortcut tile, it bounces to the desktop, opens the Windows PowerShell console, and presents the information I want. Because I specified –noprofile, the prompt is a generic black Windows PowerShell prompt—but hey, it works. This is shown here:

Image of command output

Well, I am down to 78 percent on my battery now, but that is still 155 minutes remaining. So I am good to go.

Join me tomorrow, when I have a guest blog post about DHCP written by Microsoft PFE, Ian Farr. It is an excellent two-part series, and you will 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 

Viewing all 2129 articles
Browse latest View live