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

Use PowerShell 3.0 to Find Enabled Windows 8 Features

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use Windows PowerShell 3.0 to find enabled Windows 8 features.

Microsoft Scripting Guy, Ed Wilson, is here. One of the neat things about Windows (does not matter the version) is how I can customize the installation or deployment. In fact, nearly every version of Windows I have ever worked with has had very sophisticated deployment tools. For the majority of my needs, they are a bit too sophisticated.

All I would like to do is add or remove features from a client operating system in an easy-to-use manner. In the past, I used a tool called sysocmgr. I wrote a number of rather complicated VBScript scripts to automate the use of sysocmgr. It worked, and it was the tool that I had to use to get the job done. A few years ago, Microsoft introduced DISM. This powerful tool permits easy manipulation of images. Cool.

Use the DISM cmdlets to determine enabled features

In Windows 8 with Windows PowerShell 3.0, there are a number of cmdlets supplied as part of the DISM module. These cmdlets are listed in the following table along with a synopsis of their functionality.

Name

Function

Add-AppxProvisionedPackage

Adds an AppX package that will install for each new user to a Windows image.

Use-WindowsUnattend

Applies an unattended answer file to a Windows image.

Get-AppxProvisionedPackage

Gets information about AppX packages in an image that will be installed for each new user.

Remove-AppxProvisionedPackage

Removes an AppX packages from a Windows image.

Add-AppxProvisionedPackage

Adds an AppX package that will install for each new user to a Windows image.

Add-WindowsDriver

Adds a driver to an offline Windows image.

Add-WindowsPackage

Adds a single .cab or .msu file to a Windows image.

Clear-WindowsCorruptMountPoint

Deletes all of the resources associated with a mounted image that has been corrupted.

Disable-WindowsOptionalFeature

Disables a feature in a Windows image.

Dismount-WindowsImage

Dismounts a Windows image from the directory it is mapped to.

Enable-WindowsOptionalFeature

Enables a feature in a Windows image.

Get-AppxProvisionedPackage

Gets information about AppX packages in an image that will be installed for each new user.

Get-WindowsDriver

Displays information about drivers in a Windows image.

Get-WindowsEdition

Gets edition information about a Windows image.

Get-WindowsImage

Gets information about a Windows image in a .wim or .vhd file.

Get-WindowsOptionalFeature

Gets information about optional features in a Windows image.

Get-WindowsPackage

Gets information about packages in a Windows image.

Mount-WindowsImage

Mounts a Windows image in a .wim or .vhd file to a directory on the local computer.

Remove-AppxProvisionedPackage

Removes an AppX packages from a Windows image.

Remove-WindowsDriver

Removes a driver from an offline Windows image.

Remove-WindowsPackage

Removes a package from a Windows image.

Repair-WindowsImage

Repairs a Windows image in a .wim or .vhd file.

Save-WindowsImage

Applies changes made to a mounted image to its .wim or .vhd file.

Set-WindowsEdition

Changes a Windows image to a higher edition.

Set-WindowsProductKey

Sets the product key for the Windows image.

Use-WindowsUnattend

Applies an unattended answer file to a Windows image.

Note   The Get-WindowsOptionalFeature cmdlet must run with elevated rights. Right-click the Windows PowerShell 3.0 console while holding the CTRL key, and select Run As Administrator from the action menu.

The Get-WindowsOptionalFeature cmdlet reveals information about the status of the optional Windows features. The trick, unless you really are manipulating a Windows image, is to use the online switch. When used, the online switch tells the Get-WindowsOptionalFeature cmdlet to return the status of the current installation. The syntax for this command is shown here.

Get-WindowsOptionalFeature –Online

By default, the Get-WindowsOptionalFeature returns about all information about all features—enabled, disabled, or otherwise. To return only enabled features, use the Where-Object to filter on the state property. The default display of information is a list that makes the information cumbersome to read. I like to pipe results to Format-Table and use the autosize parameter to create a nice, tight display. This technique is shown here (ft is an alias for Format-Table and –a is the partial parameter for autosize).

Get-WindowsOptionalFeature -Online | where state -eq enabled | ft –a

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

Image of command output

The command works against remote computers in addition to local ones by using Windows PowerShell remoting. I use the same technique that I have used in the past.

First, I import the Active Directory module. (This module does not exist unless the RSAT tools are installed on the local computer, or unless you use implicit remoting to bring them from a remote server.) Next, I use the Get-ADComputer cmdlet to find all of the Windows 8 computers, and then I use the Invoke-Command cmdlet to use the Get-WindowsOptionalFeature cmdlet to find the enabled optional features. This bit of code is shown here.

Get-EnabledWindowsOptionalFeatures.ps1

Import-Module activedirectory

$c = Get-ADComputer -Filter * -Properties operatingsystem |

   where operatingsystem -match 8

Invoke-Command -cn $c.name -SCRIPT {

  Get-WindowsOptionalFeature -Online |

  Where-Object state -eq enabled

   }

Join me tomorrow when I will talk about more cool things you can do with Windows PowerShell.

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

Ed Wilson, Microsoft Scripting Guy 


PowerTip: Create an ASCII File from Inside PowerShell

$
0
0

Summary: Learn how to create an ASCII file from inside Windows PowerShell.

Hey, Scripting Guy! Question I want to create an ASCII text file to hold the results of the Get-Process cmdlet. How can this be done?

               Hey, Scripting Guy! Answer

a. Pipe the results to the Out-File cmdlet and use the -encoding parameter to specify ASCII:

GPS | Out-File -FilePath c:\fso\myproc.txt -Encoding ascii

b. Use the InputObject parameter of the Out-File cmdlet and use the –encoding parameter to specify ASCII:

Out-File -InputObject (gps) -FilePath c:\fso\myproc.txt -Encoding ascii

c. Use redirection like this:

Get-Process >>c:\fso\myprocess.txt

Weekend Scripter: Use PowerShell and BITS to Simplify Downloading Large Files

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using the Windows PowerShell BITS module to download large files.

Microsoft Scripting Guy, Ed Wilson, is here. One of the cool things about my job—OK, so there are many cool things about my job—but one of the things that I just geek out on, is access to the daily builds of Windows. All day, the developers are writing code for Windows and the testers are testing the builds. At night, they are all checked-in; and all night long, we build Windows. Boom, the next day, the timer dings, and we have a fresh build of Windows.

As you may recall, the Scripting Wife and I live in Charlotte, North Carolina, and I work from home. I rarely go into the office on the Microsoft campus. In fact, the last time I was there, it was to upgrade my corpnet attached laptop from a dogfood edition of Windows 8 to the RTM bits. Testing THAT process REQUIRED a physically hardwired LAN connection. But normally, via Direct Access, I am at home in my office working away, and I rarely notice or miss not being in the office in Charlotte. (Oh, I MISS the two hour commute. REALLY, I do).

I have absolutely the fastest commercially available Internet connection in my home office (currently clocked at a little better than dual-band ISDN), so I need to make my connections count. When I was downloading the daily builds, I would select the Windows 8 32-bit, Windows 8 64-bit, Windows Server 2012, and the RSAT tools for Windows 8 (32-bit and 64-bit). This ended up being nearly 12 gigabytes of files to download. With an unreliable Internet connection, it can be very frustrating to be in the middle of a download when, BOOM, the link drops, and you have to start all over. Major bummer! Major bummer indeed!

I solved my download problem by using the BITS module. (Now, this is not a completely new idea for me, I have been using BITS for years. In fact, I was teaching a Windows PowerShell class in Edinburgh, Scotland, and downloading the daily builds of Windows Vista. I would start the download in the Microsoft office there, teach class all day, pause my download, go to the hotel, and start the download back up. I would go to dinner, and usually, by the time I was back in the hotel, the download had completed, and I could create the virtual machines and begin my testing. Back in those days, I used a VBScript script that contained a number of calls to the BITS admin utility.

BITS is worth a bit of trouble because it implements checkpoint restarts, automatic bandwidth throttling, and a number of other very useful features.

Use the BITS PowerShell module to download large files

I use the following script to create a CSV file that I use to control the way that BITS works. It lists each file to download and provides a destination for each file.

The first thing I do is specify the path for my CSV file. It is always the same file name in the same file location. Next, I specify the path to the daily builds for the server, x86 and 64-bit builds. These four lines of code are shown here.

$csvPath = "C:\fso\files.csv"

$serverPath = "\\dailybuilds\amd64fre\iso\iso_server_eval_en-us"

$clientPath = "\\dailybuilds\x86fre\iso\iso_enterprise_eval_en-us"

$client64 =  "\\dailybuilds\amd64fre\iso\iso_enterprise_eval_en-us"

If the target CSV file already exists, I rename it and provide the file with a random name. In this way, I can look back and see previous versions of the download file if required. Besides, it is a pretty cool use for the Get-Random cmdlet as shown here.

if(Test-Path $csvPath)

  { Rename-Item -Path $csvPath -NewName ("{0}.{1}.txt" -f $csvpath, (get-random).tostring()) }

I now need to add the header for my CSV file. The column headings are Source and Destination, and the code is shown here.

"source, Destination" | Out-File -FilePath $csvPath -Encoding ascii

I now need to produce a list of files to copy. The cool thing is that the Get-ChildItem cmdlet accepts an array of paths, and therefore I simply supply the three paths as an array to the cmdlet, and pipe the gather fileinfo objects down the line. This line of code is shown here.

Get-ChildItem $serverPath,$clientPath,$client64 |

Now I use the Foreach-Object cmdlet to walk through the collection and I pick up the FullName property (the full name includes the complete path to the file). Here is the cool part. I create a string. The string includes the complete path to the source file, a comma, and the complete path for the destination file. I then pipe this string to the Out-File cmdlet. I am, in effect, rolling my own CSV file. I will admit it is a bit of FrankenCode, but hey, it is my own code that I use for my own purposes (besides, K. Schulte made a comment on a recent posting that he loves FrankenCode—I am always happy to oblige).

ForEach-Object { "$($_.fullname),C:\data\win8Server\$($_.name)" } |

  Out-File -FilePath $csvPath -Encoding ascii -Append

I have now created my input file that I will use for the BITS commands. The complete script is shown here.

CreateBitsDownloadFile.ps1

$csvPath = "C:\fso\files.csv"

$serverPath = "\\dailybuilds\amd64fre\iso\iso_server_eval_en-us"

$clientPath = "\\dailybuilds\x86fre\iso\iso_enterprise_eval_en-us"

$client64 =  "\\dailybuilds\amd64fre\iso\iso_enterprise_eval_en-us"

if(Test-Path $csvPath)

  { Rename-Item -Path $csvPath -NewName ("{0}.{1}.txt" -f $csvpath, (get-random).tostring()) }

"source, Destination" | Out-File -FilePath $csvPath -Encoding ascii

Get-ChildItem $serverPath,$clientPath,$client64 |

ForEach-Object { "$($_.fullname),C:\data\win8Server\$($_.name)" } |

  Out-File -FilePath $csvPath -Encoding ascii -Append

Starting and monitoring the download

My next Windows PowerShell script is not even a script. I just type a few Windows PowerShell commands. First I import the module (I know that Windows PowerShell 3.0 automatically imports modules, but it is a bit slow, and I can easily type ipmo *bit* very fast. So I import the BITS module and start the BITS transfer.

A couple of things…I use the Import-CSV cmdlet to import my CSV file, and I pipe the information to the Start-BitsTransfer cmdlet. I specify an Asynchronous transfer and a RetryInterval of 60 seconds. For everything else, I go with the defaults. One thing that is really confusing is the priority parameter. The first time I did this, I chose HIGH because I thought that would mean a high priority. Unfortunately, the highest priority is Foreground. The ordering goes like this: Foreground, High, Normal, Low. Luckily Foreground is the default, so I just leave it there. It works for me, but keep in mind that it will suck your pipe dry. So if, for instance, your wife is trying to watch the PowerScripting Podcast while you are doing this, you WILL hear about it. These two commands are shown here.

Import-Module *bits*

Import-Csv C:\fso\files.csv |  Start-BitsTransfer -Asynchronous -retryInterval 60 

To monitor the bits jobs, I use the following command, where I look for jobs that are not transferred.

Get-BitsTransfer | ? { $_.jobstate -ne 'transferred'}

If I want to look at the statistics of my download jobs, I use the command shown here.

Get-BitsTransfer | ? { $_.jobstate -ne 'transferred'} |

select jobid, jobstate,

 @{Label="percent Complete"; EXPRESSION={($_.BytesTransferred/$_.BytesTotal*100)} }

Occasionally a BITS job will stall. But hey, this is why I use BITS in the first place. So to restart stalled jobs, I use the command shown here.

Get-BitsTransfer | ? jobstate -ne transferred | Resume-BitsTransfer -Asynchronous

If a BITS job continues to error out, it is time to get rid of it. So I use this command to delete those jobs.

Get-BitsTransfer | ? jobstate -eq error | Remove-BitsTransfer

When everything is percolating nicely, it is time to go watch an old Perry Mason rerun on my other computer. So I can keep an eye on things (and know if I have time to watch a second episode), I came up with this code. It refreshes every five minutes and lets me know the current status of the jobs.

1..1000 | ForEach-Object {

  Clear-Host ; "last update $(get-date)"

  Get-BitsTransfer |

  Where-Object { $_.jobstate -ne 'transferred'} |

  select jobid, jobstate,

   @{Label="percent Complete"; EXPRESSION={($_.BytesTransferred/$_.BytesTotal*100)} }

   sleep 300 }

WooHoo, the jobs are done. Well, how did my bandwidth do today? I always like to know if it would have been quicker to drive two hours to the Microsoft office in Charlotte to make my download. So I came up with this command to display the statistics.

Get-BitsTransfer |

% { "Job id {0} transfered {1} in {2} total minutes" -f

$_.jobid, $_.bytesTransferred,

[int](New-TimeSpan -Start $_.CreationTime -End $_.TransferCompletionTime).totalMinutes }

When it is done, I am not yet done. I have to complete my transfers. Without this command, all you will have is a bunch of non-usable files. So to complete the BITS transfer, use the Complete-BitsTransfer cmdlet as shown here.

Get-BitsTransfer | Complete-BitsTransfer

Well, I hope you find these commands useful. This is not complete documentation on the BITS cmdlets. In fact, I did not cover half of them. But these are the ones I use on a daily basis, and hence, for me anyway, they are the most useful. I worked them out over the course of the last couple of years whilst getting my daily ration of dogfood.

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 Create Color Output from Commands

$
0
0

Summary: Learn to use the Write-Host PowerShell cmdlet to create color output from commands.

Hey, Scripting Guy! Question Someone told me the Write-Host cmdlet could create color output. Can you give me some samples of acceptable syntax?

Hey, Scripting Guy! Answer

a. Write-Host -ForegroundColor 12 "hi"

b. Write-Host -ForegroundColor 12 "hi" -BackgroundColor white

c. Write-Host -ForegroundColor blue -BackgroundColor white

d. Write-Host -ForegroundColor 2 hi

e. Write-Host -backgroundcolor 2 hi

f. Write-Host -backgroundcolor ("{0:X}" -f 2) hi

     for($i=0 ; $i -le 15 ; $i++) { write-host -foregroundcolor $i "hi" }

Weekend Scripter: Automate Formatting Portable USB Drives with PowerShell

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use Windows PowerShell to automate formatting and copying data to USB drives.

Microsoft Scripting Guy, Ed Wilson, is here. Today we leave the mystery writers conference in Nashville, Tennessee and head to northern Kentucky. I will be teaching a Windows PowerShell workshop to a group of Microsoft premier customers, get to see my good friend Robert from California, speak to the first ever Cincinnati Windows PowerShell Users Group, and have dinner with some old friends. The Scripting Wife will be going with me to the Windows PowerShell Users Group meeting, enchanting local merchants, and be out visiting friends and family.

In preparation for the Windows PowerShell class, I agreed to copy a bunch of files to a bunch of USB drives. I really wanted USB 3.0 drives, but they were not available in the size and quantity that I needed. Oh well, there is always something that provides an excuse for a quick Windows PowerShell script! Yes, Windows PowerShell to the rescue!

Using PowerShell to format a drive

Like many of the things in Windows PowerShell 3.0 and Windows 8, the capabilities exist in previous versions of Windows, and they were doable even in Windows PowerShell 1.0. The difference is the ease of accomplishing the task. My Windows PowerShell story today begins with two commands. The first is the Format-Volume function (yes, I know the specific verb is a bit pushing the boundaries of use—I mean Format-List, Format-Table, Format-Wide do not necessary lead to Format-Volume, do they? Oh well. From a discoverability standpoint, the name makes sense unless you spend a lot of time searching the Help for Set-Volume, New-Volume, or even Initialize-Volume before you finally give up and use Get-Command –noun *volume*, which is how I found the command. By the way, it is not technically a cmdlet. Get-Command tells me it is a function, and it resides in the Storage module.

Anyway, I tried to use the Format-Volume function to format one of the portable USB drives, and the first thing that happened was that a prompt asked if I wished to continue. OK, so they implemented ShouldProcess. That is probably a good thing. It took a bit of playing around, but finally I discovered that to suppress the prompt (a definite requirement if I have any hopes of automating the process), I feed a value to the confirm parameter.

Note   This is not included in the documentation, but it makes sense. The length of the NewFileSystemLabel property is limited to 11 characters. You can type more, and the command does not generate an error, but when you run the command, the following warning appears in the output.

PS C:\> Format-Volume -DriveLetter e -NewFileSystemLabel PowerShellROCKS -FileSystem

exfat -Confirm:$false

WARNING: The volume label is not valid.

DriveLetter  FileSystemL FileSystem  DriveType   HealthStatu SizeRemaini        Size

             abel                                s                    ng

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

E                        exFAT       Removable   Healthy        28.89 GB    28.89 GB

Even though the warning appears, the command still completes and formats the drive. The label reverts the default label for the type of drive. In this example, the label becomes Removable Disk.

The command line is shown here.

Format-Volume -DriveLetter E -NewFileSystemLabel PowerShell -FileSystem exfat -Confirm:$false

I decided that I want to use Robocopy to perform the actual copy operation. It is built-in to Windows 8, and it is very fast. The command line I use is simple: the source, the destination and an /S switch to copy subdirectories. I use the command line shown here.

robocopy $source $destination /S

Playing system sounds

The nice thing is that Robocopy informs me the progress of each copy operation. When the process completes, I play a system sound to let me know that I can get the next drive and run the script again. Here is the code that plays a system sound.

[media.SystemSounds]::("Hand").play()

I have no idea of what the system sounds sound like, so I wrote a quick bit of code to play the system sounds to provide me with an audition. Here is the code that I used to do that.

Foreach($sound in ([media.systemsounds] | gm -static -MemberType property))

{

 $sound.Name

 [media.SystemSounds]::($sound.name).play()

 start-sleep -s 1

}

 

FormatDriveCopyFiles.ps1

#requires -version 3.0

ipmo storage

$source = "C:\data\PowerShellWOrkshop\"

$destination = "E:"

Format-Volume -DriveLetter E -NewFileSystemLabel PowerShell -FileSystem exfat -Confirm:$false

robocopy $source $destination /S

[media.SystemSounds]::("Hand").play()

When I run the script, the output from the following image displays in the Windows PowerShell ISE.

Image of command output

That is about it for today. I think there is an outlet mall the Scripting Wife wants to take me to before we check-in to the next hotel. Join me tomorrow for more Windows PowerShell 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: Check to See if a Command Completes Properly

$
0
0

Summary:  Learn how to check for proper completion of a Windows PowerShell command.

Hey, Scripting Guy! Question How can I tell if a Windows PowerShell command completes successfully?

               

 Hey, Scripting Guy! Answer

a. Query the $error automatic variable. If $error[0] reports no information, no errors have occurred.

b. Query the $? automatic variable. If $? is equal to true, the command completed successfully.

Three Cool PowerShell Service Tricks

$
0
0

Summary: Ed Wilson, the Microsoft Scripting Guy, talks about three cool Windows PowerShell tricks for working with services.

Microsoft Scripting Guy, Ed Wilson, is here. It does not matter what ones role is, whether an Exchange Server admin, a Group Policy guru, or even an ordinary every day power user, one eventually needs to work with services. Today I will show three cool tricks that involve using Windows PowerShell to work with services.

Stop multiple services at once

One of the nice features of the Get-Service cmdlet is that it accepts an array. Therefore, I can find information about specific services by supplying the name of multiple services. This technique is shown here.

PS C:\> Get-Service bits,wuauserv

 

Status   Name               DisplayName

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

Running  bits               Background Intelligent Transfer Ser...

Running  wuauserv           Windows Update

The Stop-Service cmdlet accepts an array of ServiceController objects (the type of object returned by the Get-Service cmdlet). Therefore, I can pipe the results of the Get-Service cmdlet to the Stop-Service cmdlet to stop the array of services. This command is shown here.

Get-Service bits,wuauserv | Stop-Service

To see what a command does prior to the actual execution of the command, use the WhatIf switch. In the image that follows, the use of the WhatIf switch to prototype the command appears, followed by the actual command to stop the services.

Image of command output

Start multiple services

The Start-Service cmdlet also accepts an array of ServiceController objects as pipelined input. This means that I can use Get-Service to look at my service status, and then pipe the objects to the Start-Service cmdlet if required. This command is shown here.

Image of command output

Stopping and disabling services in one command

A cool thing is that I can use the Get-Service cmdlet to check on a group of services. If I want to stop them, I can pipe the returned ServiceController object to the Stop-Service cmdlet. But what if I also do not want the services to start up on the next reboot? Here is where some really cool stuff comes into play…

I use the PassThru switch, and the ServiceController objects will pass along the pipeline. I can then use those objects with the Set-Service cmdlet and change the startup type of the services to Disabled. Here is the command to accomplish this task.

Get-Service bits,wuauserv | Stop-Service -PassThru | Set-Service -StartupType disabled

Unfortunately, although Set-Service permits setting the startup type of the service to Disabled, the Get-Service cmdlet does not report the startup type of the service. To check on the results of our command, I need to use WMI. Here is the WMI command that I use to check the start mode of the services.

gwmi win32_service -filter "name = 'bits' OR name = 'wuauserv'"

The command and the associate output from the command are shown in the image that follows.

Image of command output

Join me tomorrow when I will talk about more way 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: A Couple Quick PowerShell Array Tricks

$
0
0

Summary:  Learn some quick tricks for using Windows PowerShell arrays.

Hey, Scripting Guy! Question How can I split the following string in the $a variable?

$a = "atl-ws-01,atl-ws-02,atl-ws-03,atl-ws-04"

Hey, Scripting Guy! Answer Use the split method :

$b = $a.split(",")

 

Hey, Scripting Guy! Question How do I join an array, such as the one in the $a variable shown here?

 $a = "h","e","l","l","o"

Hey, Scripting Guy! Answer Use the join static method from the string c


Build Your SharePoint Internet Presence with PowerShell

$
0
0

Summary: Learn about using Windows PowerShell to automate SharePoint.

Microsoft Scripting Guy, Ed Wilson, is here. Today we have a guest blog by Ryan Dennis.

Photo of Ryan Dennis

Ryan Dennis is a senior SharePoint engineer for Information Control Corporation (ICC) in Columbus, Ohio.  Ryan is a Microsoft Certified IT Professional (MCITP) and a Microsoft Virtual Technology Specialist (vTSP) in SharePoint 2010. An accomplished blogger and speaker, he has worked on SharePoint solutions in the public, non-profit, and private sectors. He focuses primarily on SharePoint architecture, automation, and middle-tier development leveraging out-of-the-box features. Ryan has worked on projects ranging from large-scale Intranet deployments to secure extranets as well as public-facing Internet site deployments. Ryan has a passion for automation, whether it is automating business processes through forms and workflow; or automating deployment, migration, and configuration using Windows PowerShell.

Ryan is one of the speakers for the Windows PowerShell Saturday event in Charlotte, North Carolina that takes place on September 15, 2012. Ryan will be speaking about using Windows PowerShell to manage SharePoint.

Blog: SHAREPOINTRYAN.COM
Twitter: http://twitter.com/SharePointRyan

Take it away Ryan…

SharePoint has been gaining a lot of traction as the web content management platform of choice for companies looking to upgrade their public-facing websites. One of the primary reasons behind this shift is that companies may already be using SharePoint for their intranet or extranet platforms, so they already have the skills, licenses, and so on to support that scenario.

There are a lot of pieces to the SharePoint for Internet sites puzzle, but some of the key pieces are related to branding, search engine optimization, and performance. That is, the site must have an elegant user interface, it should be easily crawled by search engines (such as Bing, Google, and Yahoo), and it must be optimized and cached in a way that yields solid performance.

By utilizing Windows PowerShell as an automation tool, SharePoint Internet site deployments can be automated essentially from start to finish, which can make builds, migrations and multifarm code promotion a breeze!

Using PowerShell to automate the website build

SharePoint 2010 shipped with over 500 Windows PowerShell cmdlets. Among these are cmdlets for creating web applications, content databases, site collections, and subsites. To develop a robust, elegant solution for quickly deploying complete sites, I have leaned on Windows PowerShell and XML as my two primary tools. Windows PowerShell gives us so many good cmdlets right out of the box, but the strength of Windows PowerShell is the ability to extend it by using scripts and advanced functions.

The code I am looking forward to sharing at Windows PowerShell Saturday 002 in Charlotte, North Carolina is the result of months of testing, enhancing, and more testing…and it is quite a beauty. This advanced function consists of over 700 lines of Windows PowerShell code, but I’ll break it down into a few chunks for the purposes of this post.

At a high-level, the code will do the following:

  1. Create one or more web applications
  2. Create a root site collection
  3. Configure BLOB and output caching
  4. Activate additional SharePoint features
  5. Create an enterprise search center site collection
  6. Configure search settings
  7. Create subsites
  8. Create pages
  9. Warm-up the site
  10. Launch the site in Internet Explorer when complete

Building the form dialog

One of my favorite things about Windows PowerShell is its ability to render Windows Forms by using what is essentially .NET code. For the purposes of my New-SPWebApplicationFromXml function, I launch a Windows Form to allow the user to select one or more web applications from their XML file. This will allow them to potentially create multiple web applications in one shot—a great use case for things like moving from a development environment to a staging or production environment. The code to get started with a form dialog is pretty much as simple as this:

[POWERSHELL CODE]

# Load Assemblies for System.Windows.Forms and System.Drawing #

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

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

$objForm = New-Object System.Windows.Forms.Form

$objForm.Text = "SharePoint Web Application Deployment Wizard"

$objForm.Size = New-Object System.Drawing.Size(500,450)

$objForm.StartPosition = "CenterScreen"

$objForm.Icon = $Img

$objForm.FormBorderStyle = 'FixedDialog'
[void] $objForm.ShowDialog()

[END POWERSHELL CODE]

Running that code will give you this form:

Image of form

That’s a pretty good start, and we can start to add other objects to the form to really make this thing sing—for example, a list box for selecting the web applications that we’ll grab from the XML file. For the full form, you’ll have to come to Windows PowerShell Saturday!

Getting the XML content

Possibly my favorite thing about Windows PowerShell is its ability to read and understand XML at a very high level. By storing the data that the script needs in XML, it allows the script to be very generic in that nothing is hard-coded, and it uses the XML file to perform its work. In addition, it prevents having to enter lots of parameters in the console.

Here is a snippet of my XML file that is used to create the web application:

[XML CODE]

<Name>Vandelay Industries</Name>

<AppPool>SharePoint - VandelayDemo</AppPool>

<AppPoolAccount>ISG1085\SpAppPool</AppPoolAccount>

<DBServer>ISG1085\SharePoint</DBServer>

<DBName>SP2010_Content_Vandelay_Demo</DBName>

<HostHeader>www.vandelay.com</HostHeader>

<InetpubPath>C:\inetpub\wwwroot\wss\VirtualDirectories</InetpubPath>

<Port>80</Port>

<Protocol>http</Protocol>

<ManagedPaths>

            <ManagedPath Type="explicit">search</ManagedPath>

</ManagedPaths>                                            

[END XML CODE]

You can see that in the XML, I’m providing all of the bits that we’ll need later to actually create the web application, content database, managed paths, and so on.

Using the ForEach object and SharePoint cmdlets to do the work

After we’ve provided the XML input parameter to the script, and we’ve used a nice form to select the web applications that we want to deploy. We can simply click the OK button in the form to run the script. The actual script uses a lot of ForEach looping to iterate through each selected web application, each site collection within the XML, each site within the XML, and each page within the XML.

Here is a snippet of the primary Windows PowerShell code that creates the web applications:

[POWERSHELL CODE]

if($AuthType -eq "Classic"){

                        try {

                                    # Create the Web App #

                                    New-SPWebApplication -Name $Name -ApplicationPool $ApplicationPool `

                                    -ApplicationPoolAccount $ApplicationPoolAccount -DatabaseName $DatabaseName `

                                    -DatabaseServer $DatabaseServer -HostHeader $HostHeader -Port $Port `

                                    -Path $WebsitePath -Url $HostHeader -WarningAction SilentlyContinue | Out-Null

                        }

                        catch {throw "Unable to create the web application"}

            }

[END POWERSHELL CODE]

In this code snippet, I use an if statement to run this code if the Authentication Type specified in the XML is Classic. Although claims-based authentication is the way going forward, in this example, I use Classic. I then use a try/catch block to create the web application by using the New-SPWebApplication cmdlet. I provide all of the parameters needed from variables that have been created already to grab the content from the XML file. I pipe my output to the Out-Null cmdlet to prevent the returned web application object from showing up in the console.

Putting it all together

Now that we’ve seen some of the things we can do, here are some screenshots to illustrate the flow of the advanced function:

[POWERSHELL SNIPPET]

PS>New-SPWebApplicationFromXml –XmlInput .\DemoSites.xml

[END SNIPPET]

Running the previous line (after dot-sourcing the script file) will result in launching the form dialog and displaying all the web applications that exist in the XML file:

Image of dialog

When we click OK, the script will start to run, and its progress will be constantly updated by using the built-in Write-Progress cmdlet as shown here.

Image of command output

In this post, we’ve looked at creating windows forms; leveraging XML as the input for scripts; and creating the web applications, site collections, sites, and pages by using Windows PowerShell. Although I didn’t show you all of the code, I hope that this has been informative, and if you come out to the second ever Windows PowerShell Saturday in Charlotte, NC on September 15, you’ll see the full story and hopefully leave with lots of great ideas about how to take Windows PowerShell to the next level!

~Ryan

I want to thank Ryan for taking the time to come to Charlotte, North Carolina to speak at Windows PowerShell Saturday. I also want to thank him for writing this most excellent blog. If you have questions about using Windows PowerShell and SharePoint, come to Windows PowerShell Saturday and ask Ryan.

Join me tomorrow for 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: Use PowerShell to Help Build Paths

$
0
0

Summary: Use Windows PowerShell to build a path to the system32 directory.

Hey, Scripting Guy! Question I need to build a path to the Windows\system32 directory. How can I do this?

 

Hey, Scripting Guy! Answer Join-Path -path (get-item env:\windir).value -ChildPath system32

Create, Load and Use PowerShell Modules

$
0
0

Summary: Microsoft PFE, Chris Weaver, talks about creating loading and using Windows PowerShell modules.

Microsoft Scripting Guy, Ed Wilson, is here. Today Chris Weaver is going to share a preview of his presentation for Windows PowerShell Saturday on September 15 in Charlotte NC. Hope you are planning to register.

Photo of Chris Weaver

Chris has been working for Microsoft since 2008. In the summer of 2010, he joined the PFE group as a dedicated engineer supporting several premier customers for SharePoint and all the processes around it, including migration, disaster recovery, and high availability. Chris is a big advocate of using Windows PowerShell with SharePoint, and he has several projects on the go related to SharePoint.

Take it away Chris!

Hey all,

On 9/15/2012, I’m going to be presenting at Windows PowerShell Saturday in Charlotte, NC. I could not be happier. This is an amazing chance for administrators of all knowledge levels to learn something about Windows PowerShell from some extremely passionate people.

To give you a little sneak peak at what I will present, here is something from my presentation, Windows PowerShell 101: Intro to Scripting. This will be an introduction about how you can use Windows PowerShell to help yourself at work, how to use cmdlets to answer questions, and how to use modules to improve your scripts. You will learn just how easy it is to create, load, and review modules. 

Image of code

As you can see from the previous snippet, I will be using simple code samples, and I will show you how to format results from cmdlets for readability, how to pipe output from one cmdlet into another for simpler code, and how to filter that output to give you only the results you want.

Image of slide

As you can see from the previous snippet, I’m trying to make my presentation relatable so that you can see how Windows PowerShell could be applied to your work at the office. I hope to get lots of questions, so bring them with you.

~Chris

Thank you, Chris, for this preview. Join me tomorrow for another preview of a presentation for Windows PowerShell Saturday #002.

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: Accessing System Values

$
0
0

Summary: Use Windows PowerShell to ease access to system values.

Hey, Scripting Guy! Question How can l print out the value of %systemroot%?

Hey, Scripting Guy! Answer 

a. (get-item Env:\systemroot).value

b. $env:systemroot

Finding Your Way with PowerShell Cmdlets

$
0
0

Summary: Guest blogger, Jason Walker, discusses finding the right Windows PowerShell cmdlet for the job.

Microsoft Scripting Guy, Ed Wilson, is here. Today is the preview for Jason Walker’s presentation for PowerShell Saturday #002 coming to Charlotte, NC on September 15, 2012.

Photo of Jason Walker

Jason is a Microsoft premier field engineer and Windows PowerShell evangelist. He supports customers in the public sector. He has expertise in Exchange Server, security, and Windows PowerShell. Jason has been a featured guest blogger on the Hey, Scripting Guy! Blog, and he maintains his personal blog.

Twitter: AutomationJason

Take it away Jason…

Many IT admins have been staying away from Windows PowerShell. Maybe they find the command line to be intimidating. They like to work within the GUI because one can easily figure out what to do because it’s discoverable. Little do they know little time is needed to master the skills to make Windows PowerShell discoverable. Windows PowerShell is so awesome that it has the ability to teach you how to use it.

These are some of the topics I will touch on to help you get past the beginner barrier for using Windows PowerShell.

Q: I know what I what to get done, but how do I know which cmdlet to use?

A: The use of Get-Command and a wildcard character is all you need. Let’s say you are working with services. Here is how to get all the commands that work with services:

Image of command output

Q: That’s great, but I still don’t know how to use them.

A: Don’t sweat the small stuff. Use the Get-Help cmdlet with the Examples switch.

Image of command output

Check it out. Windows PowerShell doesn’t only give you syntax that is hard to understand like other command-line utilities. It gives you practical examples. How cool is that!

Q: I’ve been using Windows PowerShell for a while now, but there is much I still don’t understand. I read on the Hey, Scripting Guy! Blog that I can get drive free space by running this command:

Get-WmiObject win32_logicaldisk -Filter "DriveType=3"

I get the Get-WmiObject part, but what does “DriveType=3” mean?

A: The documentation that explains this is on MSDN. Go to www.Bing.com, and search for “win32_logicaldisk msdn”.

I will show you how easily you can find it if you come to the Charlotte Windows PowerShell Saturday on September 15.

~Jason

Thank you, Jason, for sharing a sneak preview of your presentation. Join me tomorrow for a blog by June Blender.

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

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Display and Write Output

$
0
0

Summary: Learn to display output and write it to a text file.

Hey, Scripting Guy! Question I need to display process output at the Windows PowerShell prompt and write that same output to a text file. How can I do this?

Hey, Scripting Guy! Answer Get-process | Tee-Object -FilePath c:\fso\proc.txt

Understanding and Using Updatable PowerShell Help

$
0
0

Summary: Learn how to use the updatable Help feature in Windows PowerShell.

Microsoft Scripting Guy, Ed Wilson, is here. Our guest blogger today is June Blender.

Photo of June Blender

June Blender is a senior programming writer on the Windows PowerShell team at Microsoft, an avid Windows PowerShell user, and a passionate user advocate. She writes the Help topics that you see when you type Get-Help. She lives in magnificent Escalante, Utah, where she works remotely when she's not out hiking, kayaking, or convincing lost tourists to try Windows PowerShell. She believes that outstanding documentation is a collaborative effort, and she welcomes your comments and contributions for Windows PowerShell Help.

Twitter: @juneb_get_help
Windows PowerShell Team Blog

And now … here is June!

How I learned to love Updatable Help

There are many approaches for writing a Help system, and you've probably seen them all. There's the traditional authoritative "Father Knows Best" approach that churns out topics that the developers like. The poor writer sits in isolation tossing topics over the fence and hoping they're really helpful without really knowing. There's the modern wiki approach where you trust your customers to write your Help system. It's cheap (almost free), but rarely comprehensive and with quality that varies from terrific, to "What were they thinking?," and everything in between.

To be honest, we designed the Windows PowerShell Help system in the traditional way, but I'm not the type to sit in isolation. In fact, if you know me, you'll know that I don't sit much at all. So, I tossed myself over the fence with the topics and listened carefully to the feedback.

I realized that the best Help is collaborative. It combines the knowledge of the design team to explain the intent of a feature, the development team to explain how the feature works, the test team to point out "gotchas," beginning users to identify missing instructions that we assumed everyone knew, intermediate users to explain how the feature works in the real world and to satisfy multiple learning styles, and advanced users to show us ways of using a feature that we never even anticipated. In this collaboration, the writer provides a point of contact, technical expertise, a logical framework, and clear simple language.

Beginning in Windows PowerShell 2.0, we tried this approach, and users really appreciated it. I added dozens of examples, corrected errors, simplified and explicated, rewrote sections, and added new About topics—some of them written by users. (Did you know that Kirk Munro of Posholic.com fame wrote about_Operator_Precedence?) We added a Documentation Bug section to the Windows PowerShell page on Microsoft Connect, I started the Windows PowerShell Community Documentation Review, and I encouraged users to write directly to me (juneb@microsoft.com) and to tweet bugs and suggestions (@juneb_get_help). And you did! Thank you!

But our publishing system didn't support our collaborative model. Our writing deadlines precede code deadlines by 6-8 weeks, almost guaranteeing that the Help is outdated before it's shipped, and we couldn't correct the Help files that we shipped, because they're part of Windows. So, we updated the online version of the Help topics in the TechNet Library and told you to use the online Help whenever possible. But that strategy didn't fit the shell model, where Help is at the command prompt.

The solution, Updatable Help, is the brain-child of Dan Harman, a Windows PowerShell senior program manager. If you love Updatable Help, you need to thank Dan. Updatable Help downloads and installs the latest Help files on your computer. When you have the Help files, you simply type Get-Help. You don't even need to restart Windows PowerShell.

You can download the Help files from the Internet, but if you're not connected to the Internet, you can download them from a local file share. Administrators can use a Group Policy setting to specify a file share and prevent users from downloading Help from the Internet. And you can set it up to work automatically so you never have to think about it. Best of all, anyone who authors a module can support Updatable Help.

The Update-Help cmdlet

The foundation of Updatable Help is the Update-Help cmdlet. This is one of the most powerful and comprehensive cmdlets in Windows PowerShell.

Here's what Update-Help does by default:

  1. Finds all of the modules that are installed on your computer (in the value of the PSModulePath environment variable) plus those in the current session.
  2. Finds the online location of Help files for each module.
  3. Checks to see if you have the latest Help files for the module on your computer. 
  4. Downloads the newest Help files if you don't have them.
  5. Unpacks the Help files (they're in CAB files).
  6. Verifies the XML and file types for security.
  7. Installs them in the language-specific subdirectory of the module directory.

You just sit and smile, thinking about what it would have been like if you had to do this manually. When it's done, you type Get-Help. You don't even need to restart Windows PowerShell. Every time I run Update-Help, I feel like I applauding.

As you might expect, Update-Help has lots of parameters that you can use to customize the process, including specifying the modules and the locales, and using Verbose to watch each step of the process.

And you don't even need to remember to type Update-Help. You can set it as a scheduled task or scheduled job, or put an Update-Help command in your Windows PowerShell profile. There's a built-in throttle that prevents Update-Help from running more than once each day.

If you don’t have the Help files, Update-Help prompts you to install them (once for each user on each computer). If you say yes, it runs Update-Help. If you say no, and Get-Help detects that you don't have the Help files, it auto-generates a rudimentary Help file for each command from the code, much like Get-Command.

Using Windows PowerShell 2.0? Sorry, but Updatable Help isn't supported. If you're using Windows 8 or Windows Server 2012, which have both Windows PowerShell 2.0 and 3.0, switch to Windows PowerShell 3.0 (type PowerShell or PowerShell.exe) before running Update-Help.

No Internet? Use the Save-Help cmdlet

If you have computers that aren't connected to the Internet or you don't want thousands of client machines accessing Internet downloads, there's the companion Save-Help cmdlet.

Save-Help works a lot like Update-Help, but it doesn't unpack and install the Help files on your computer. Instead, it saves the Help file package for each module in a file system directory that you specify. When users need to update Help, they use the SourcePath parameter of the Update-Help cmdlet to tell Update-Help to get the Help files from the file share instead of from the Internet.

Administrators can prevent users from downloading Help from the Internet. The "Set the default source path for Update-Help" Group Policy setting specifies a file system location for value of the SourcePath parameter. When users type Update-Help, they get the Help from the file system directory automatically. Users can override the default source path with an alternate file system location, but they can't eliminate the SourcePath parameter and then use Update-Help to download Help files from the Internet.

Enhanced online Help

There are a few gotchas, as always. To update Help for modules that are installed in the Windows PowerShell installation directory, $pshome, you need to start Windows PowerShell with the "Run as administrator" option. Otherwise, you get an "access denied" error. To run as administrator, you need to be a member of the Adminstrators group on the computer, and not everyone is.

To provide extra help to users who cannot download Help files, we've improved the online Help experience in Windows PowerShell. In Windows PowerShell 2.0, Get-Help -Online works only when the Help files are on the computer. That's because the URL (the Internet address) of the online version of the Help topic is in the Help file in the first related link.

In Windows PowerShell 3.0, the Internet address of the Help topic for a cmdlet is part of the cmdlet (it's the HelpUri property value). So if you have the cmdlet, you have the link. This works for all types of commands, including simple and advanced functions, CIM commands, and workflows.

Read all about it!

You can read all about Updatable Help in about_Updatable_Help and in the Help topics for the Update-Help and Save-Help cmdlets.

If you want to add Updatable Help and online Help to modules that you author, you can learn how in Supporting Updatable Help and Supporting Online Help.

If you're interested in the nitty-gritty internals (I always am), I snuck a really detailed How Updatable Help Works into the SDK topics.

Troubleshooting Updatable Help

Here's the "call to action" part. I'd like to work with you to produce an outstanding guide for troubleshooting problems with Updatable Help. I'm adding a moderated (by me) troubleshooting page to the TechNet Wiki, but I'll also accept questions, suggestions, and solutions by e-mail (juneb@microsoft.com), the Windows PowerShell page on Microsoft Connect, and Twitter (@juneb_get_help)—and in person, of course.

Here are some of the obvious issues:

  • Some modules do not support Updatable Help, so you're not going to be able to update your Help files. Update-Help skips these by default. To find modules that support Updatable Help, use:

Get-Module –ListAvailable | where HelpInfoUri
 (Get-Module <ModuleName>).HelpInfoUri

  • Some modules support Updatable Help, but they don’t yet have any Updatable Help files in their Internet location. The error message says, "The HelpInfoUri does not resolve to  a container." Nothing you can do but wait. (This error also appears when the HelpInfoUri or module GUID in the HelpInfo XML file is wrong.)
  • Network connection issues. The error message says, "Unable to retrieve the HelpInfo XML file."  There might be a problem with the XML file, but often this is a network issue. Retry.
  • I can't see the Updatable Help files for Windows modules in their download location. I went to the URL that's in the value of the HelpInfoUri property, but didn't see anything.

  • The Help files for Windows modules are stored in an Internet location that doesn't have any web pages. It only contains the files, so there's nothing to see.

  • For which system modules have I downloaded Updatable Help?

    (Hint: Look for a HelpInfo XML file.)

Split-Path (dir $pshome\Modules\*HelpInfo.xml -Recurse).Directory -Leaf

  • How do I tell which version of a module's Help files I have installed?

#Get-UpdateHelpVersion.ps1
Param
      (
         [parameter(Mandatory=$False)]
         [String[]]
         $Module
      )      
$HelpInfoNamespace = @{helpInfo="http://schemas.microsoft.com/powershell/help/2010/05"}

if ($Module) { $Modules = Get-Module $Module -ListAvailable | where {$_.HelpInfoUri} }
else { $Modules = Get-Module -ListAvailable | where {$_.HelpInfoUri} }

foreach ($mModule in $Modules)
{
    $mDir = $mModule.ModuleBase

    if (Test-Path $mdir\*helpinfo.xml)
    {
        $mName=$mModule.Name
        $mNodes = dir $mdir\*helpinfo.xml -ErrorAction SilentlyContinue | Select-Xml -Namespace $HelpInfoNamespace -XPath "//helpInfo:UICulture"
        foreach ($mNode in $mNodes)
        {
            $mCulture=$mNode.Node.UICultureName
            $mVer=$mNode.Node.UICultureVersion
            
            [PSCustomObject]@{"ModuleName"=$mName; "Culture"=$mCulture; "Version"=$mVer}
        }
    }
}

 

~June Blender
Updatable Help: Because stale Help is so v2.

Thanks for sharing, June. Join me tomorrow when we will have another exciting day using Windows PowerShell.

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

Ed Wilson, Microsoft Scripting Guy


PowerTip: Display the Character for an ASCII Value

$
0
0

Summary: Learn a simple trick to display the character associated with an ASCII value.

Hey, Scripting Guy! Question I would like to display the ascii character associated with the ascii value 56. How can I do this?

Hey, Scripting Guy! Answer [char]56

Weekend Scripter: Discover the Power of WMI and PowerShell

$
0
0

Summary: Guest blogger, Brian Wilhite, talks about using Windows PowerShell and WMI in the enterprise.

Microsoft Scripting Guy, Ed Wilson, is here. Brian Wilhite is with us today to share a preview of his presentation for Windows PowerShell Saturday, whiche is coming to you in two weeks on September 15 in Charlotte. NC.

Photo of Brian Wilhite

If you’re like me and most system administrators, you are challenged daily to do more with less. Windows PowerShell, coupled with WMI, is one awesome duo, like Magic/Kareem, Jordan/Pippen, or Kobe/Shaq—you get the idea. With this duo, you know that you’ll be able to get the job done quickly, effectively, and efficiently. I use Windows PowerShell and WMI frequently, especially when my manager asks questions like, “How many computers do we have in our environment that are running Windows 2003 Server with Service Pack 1 or less?” Obviously, Windows PowerShell and WMI are on the top of my list when addressing this very question in a timely manner.

With the release of Windows 8 and Windows Server 2012, a few new players emerge that will change the way we interact with the CIM/WMI model within Windows. If you’re not familiar with these new “players,” you can quickly identify them with the following Windows PowerShell one-liner:

Image of command output

As I briefly mentioned earlier, if someone needs information quickly, and you don’t quite remember what WMI class has the particulars needed, Get-CimClass comes to the rescue. I know I’m going to need server name, operating system, and service pack data elements, so what class has that information? I could run Get-CimClass and wade through all 1100 WMI classes to try to find what I need, or I could simply run the following Windows PowerShell command and pinpoint exactly what I’m looking for.

Image of command output

The Win32_OperatingSystem WMI class looks like something I can use and it appears to have a property similar to “Service Pack.”

I’ve run out of time for now, but the good news is that there is more to come on September 15, when we will get deeper into detail with my “Discovering the Power of WMI and PowerShell in the Enterprise” session at the second Windows PowerShell Saturday.

~Brian

Thank you, Brian, for sharing this sneak peek.

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: Discover Short PowerShell Aliases

$
0
0

Summary: Use wildcard characters to find Windows PowerShell cmdlet aliases.

Hey, Scripting Guy! Question How can I display all one-letter Windows PowerShell cmdlet aliases?

Hey, Scripting Guy! Answer Get-Alias ?

Weekend Scripter: Use PowerShell to Manage Office 365

$
0
0

Summary: Use Windows PowerShell to manage your Office 365 environment.

Microsoft Scripting Guy, Ed Wilson, is here. Today we have as our guest blogger, Alan Byrne.

Photo of Alan Byrne

Alan is the cofounder of Cogmotive Reports, an Office 365 Reporting and Analytics web application that offers a range of automated Office 365 reports on mailbox sizes, user log-in times, mobile devices, license usage, and several other Office 365 metrics. He has an extensive background in design and administration for Windows and Exchange Server, and he tries to script every administration task he comes across. More recently, Alan has been applying these skills to Microsoft Office 365.

Twitter: @cogmotive
Website: Cogmotive Reports

Export a license reconciliation report

As more companies move to Microsoft Office 365, IT managers need to find a way to reconcile their cloud-based licenses with their actual user numbers. No one wants to pay for licenses that they aren’t using!

If you log in to the Microsoft Office 365 portal, you can see how many licenses you’ve purchased and how many are in use. Unfortunately, there is no way to easily tell which license has been assigned to which user account.

Image of tab

To get a detailed license usage report we need to do some fancy Office 365 Windows PowerShell scripting, which I’ll explain here today.

Before we do that, we need to understand how licenses work in Office 365. An Office 365 tenant can hold many different license types; each license type is called a subscription. This allows administrators to assign a feature set to one group of users that is different than those of another group. On the Microsoft Office 365 Plans and Pricing page, you can find an explanation of what you can access with each subscription.

Within each subscription there are a set of services that you can turn on or off for each user.

Image of tab

So if you have a lot of users, how can you tell which features are enabled for each person? Well, you can click each user one-by-one and note it—or you can script it.

Microsoft allows you to administer Office 365 remotely by using Windows PowerShell. The script that I am presenting today uses this functionality to generate a CSV file that you can import into Microsoft Excel to view and filter your license types.

For this script to work, you need to install the Microsoft Online Services Module for Office 365. This allows your local Windows PowerShell to utilize the Microsoft Office 365-specific cmdlets.

To download this module, click the following link that matches your operating system version.

The script

The script begins by defining a look-up table that turns the Microsoft Subscription SKUs into something that we mere mortals can understand. We use this hash table when building the CSV file later in the script.

# Define Hashtables for lookup

$Sku = @{

            "DESKLESSPACK" = "Office 365 (Plan K1)"

            "DESKLESSWOFFPACK" = "Office 365 (Plan K2)"

            "LITEPACK" = "Office 365 (Plan P1)"

            "EXCHANGESTANDARD" = "Office 365 Exchange Online Only"

            "STANDARDPACK" = "Office 365 (Plan E1)"

            "STANDARDWOFFPACK" = "Office 365 (Plan E2)"

            "ENTERPRISEPACK" = "Office 365 (Plan E3)"

            "ENTERPRISEPACKLRG" = "Office 365 (Plan E3)"

            "ENTERPRISEWITHSCAL" = "Office 365 (Plan E4)"

            "STANDARDPACK_STUDENT" = "Office 365 (Plan A1) for Students"

            "STANDARDWOFFPACKPACK_STUDENT" = "Office 365 (Plan A2) for Students"

            "ENTERPRISEPACK_STUDENT" = "Office 365 (Plan A3) for Students"

            "ENTERPRISEWITHSCAL_STUDENT" = "Office 365 (Plan A4) for Students"

            "STANDARDPACK_FACULTY" = "Office 365 (Plan A1) for Faculty"

            "STANDARDWOFFPACKPACK_FACULTY" = "Office 365 (Plan A2) for Faculty"

            "ENTERPRISEPACK_FACULTY" = "Office 365 (Plan A3) for Faculty"

            "ENTERPRISEWITHSCAL_FACULTY" = "Office 365 (Plan A4) for Faculty"

            "ENTERPRISEPACK_B_PILOT" = "Office 365 (Enterprise Preview)"

            "STANDARD_B_PILOT" = "Office 365 (Small Business Preview)"

            }          

We also set the name and path of the file we will use for our License Usage Report CSV file. You can change this part if you want the file to be named or saved differently.

# The Output will be written to this file in the current working directory

$LogFile = "Office_365_Licenses.csv"

Now it’s time to import the Office 365 Windows PowerShell cmdlets and prompt you for your Office 365 user name and password. You should enter the details for an Administrator account for your tenant, which the script will then use to connect to Office 365.

# Connect to Microsoft Online

Import-Module MSOnline

Connect-MsolService -Credential $Office365credentials

When we’re connected to Office 365, we request a list of the subscriptions that you’ve got attached to your tenant. We use the Office 365 Get-MSOLAccountSku cmdlet for this, and we’re only interested in subscriptions that have been assigned to at least one user.

$licensetype = Get-MsolAccountSku | Where {$_.ConsumedUnits -ge 1}

The subscriptions are stored in the $licensetype variable, which we loop through to find which subscriptions are assigned to each user.

foreach ($license in $licensetype)

Before we get started on the users, we write a header line into the CSV file, which explains what each column means. This header will vary depending on which subscriptions you have attached to your tenant. Each subscription gets a new header in the output file. We use a switch statement with the wildcard parameter to make sure that we’re displaying the correct product. This is one of the most powerful switch statements I’ve come across in any scripting language.

# Build and write the header for the CSV file

            $headerstring = "DisplayName,UserPrincipalName,AccountSku"    

            foreach ($row in $($license.ServiceStatus)) {

                       

                        # Build header string

                        switch -wildcard ($($row.ServicePlan.servicename))

                        {

                                    "EXC*" { $thisLicense = "Exchange Online" }

                                    "MCO*" { $thisLicense = "Lync Online" }

                                    "LYN*" { $thisLicense = "Lync Online" }

                                    "OFF*" { $thisLicense = "Office Profesional Plus" }

                                    "SHA*" { $thisLicense = "Sharepoint Online" }

                                    "*WAC*" { $thisLicense = "Office Web Apps" }

                                    "WAC*" { $thisLicense = "Office Web Apps" }

                                    default { $thisLicense = $row.ServicePlan.servicename }

                        }

                       

                        $headerstring = ($headerstring + "," + $thisLicense)         }

            Out-File -FilePath $LogFile -InputObject $headerstring -Encoding UTF8 –append

We’re now ready to start collecting the user data. We use the Get-MSOLUser cmdlet to return a collection of user objects of all the licensed users within the subscription we’re currently processing.

$users = Get-MsolUser -all | where {$_.isLicensed -eq "True" -and $_.licenses[0].accountskuid.tostring() -eq $license.accountskuid}

With the $users variable now full of users, we loop through each one of them and write their details to the CSV report. This is where we use the hash table we created earlier to write the licenses in English.

# Loop through all users and write them to the CSV file

            foreach ($user in $users) {

 

                        $datastring = ($user.displayname + "," + $user.userprincipalname + "," + $Sku.Item($user.licenses[0].AccountSku.SkuPartNumber))

                       

                        foreach ($row in $($user.licenses[0].servicestatus)) {

                                   

                                    # Build data string

                                    $datastring = ($datastring + "," + $($row.provisioningstatus))

                                    }

                       

                        Out-File -FilePath $LogFile -InputObject $datastring -Encoding UTF8 –append

            }

To use the script for yourself:

  1. Run the Windows PowerShell script.
  2. Enter your Office 365 Admin credentials.
  3. Open the licencing report CSV file that we generated in Excel, and you should see something like the following spreadheet.

Image of spreadsheet

Armed with this license report, you could potentially save your company money by identifying incorrectly assigned licenses, such as users who have left the organization or accidentally licensed shared mailboxes.

The full script is available to view and download in the Script Center Repository.

~Alan

Thank you Alan, this is great information.

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

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Displaying the value of pi

$
0
0

Summary: Learn to obtain the value of pi.

Hey, Scripting Guy! Question How can I obtain the value of pi?

Hey, Scripting Guy! Answer

a. [math]::pi

b. 22/7

Viewing all 3333 articles
Browse latest View live


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