LeoPonti Blog

  • Use PowerShell to Create New Printer Ports

    Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell 3.0 to create new printer ports in Windows 8.

    Microsoft Scripting Guy, Ed Wilson, is here. One of the exciting things that is happening around the Scripting House is the appearance of new Windows PowerShell Saturday events. We have new events coming up in Atlanta, Singapore, and Charlotte. For information about these and other events, check out my site, Scripting Community. If you do not know what Windows PowerShell is, check out my blog post, Community: All about PowerShell Saturday.

    To programmatically create a working printer, there are at least three steps:

    1. Create the printer port.
    2. Install the printer driver.
    3. Install the printer (by using the printer port and the printer driver).

    Today I am talking about creating the printer port.

    Using PowerShell to work with printer ports

    Before I create anything, I like to know what I have going on with my computer. I can use the Get-PrinterPort function to list existing printer ports on my local computer:

    Get-PrinterPort

    I can also use this function to retrieve printer port information from a remote server running Windows Server 2008 and Windows PowerShell 3.0 as shown here:

    Get-PrinterPort -ComputerName dc1

    The commands and the output from the commands are shown in the following image.

    Image of command output

    Adding a new printer port

    To add a new printer port, I use the Add-PrinterPort function in Windows 8 or Windows Server 2012. By using the Add-PrinterPort function, I can add a local printer port, a TCP printer port, or an LPR printer port.

    Most of the time, if I am creating a local printer port, I want to print directly to a printer on the network. Doing this bypasses a print server. Therefore, in the case of large print jobs, I lose flexibility because my laptop must remain on to manage the large print job. But for short documents, it is fast. Also by printing directly to the printer, I can configure things the way that I want.

    By using Windows PowerShell, it is easy to create a TCP printer port. I use the Add-PrinterPort function, create a name for the port (the name does not matter, but it is best to use something that makes sense in the printing context). The IP address of the printer itself becomes the value for the PrinterHostAddress parameter. Here is the command I used:

    Add-PrinterPort -Name 'HP_Direct:' -PrinterHostAddress '192.168.1.88'

    I do not need to specify a value for the port number unless the printer is configured to use a different value than the default. The Add-PrinterPort function has four parameter sets, and I use the third one to create a TCP printer port. Here are the optional parameters for this parameter set:

    Add-PrinterPort [-Name] <String> [-PrinterHostAddress] <String> [-AsJob

     [<SwitchParameter>]] [-CimSession <CimSession>] [-ComputerName <String>]

     [-PortNumber <UInt32>] [-SNMP <UInt32>] [-SNMPCommunity <String>]

     [-ThrottleLimit <Int32>] [-Confirm [<SwitchParameter>]] [-WhatIf

     [<SwitchParameter>]] [<CommonParameters>]

    I have SNMP turned off on my network, so I do not need to specify a community string or any of that stuff.

    When I add a printer port, I do not need an elevated Windows PowerShell console. In Windows 8, I can do this without additional rights. In addition, Windows PowerShell does not make any checks. Therefore, if the IP address is wrong or inaccessible, no warnings generate. This is shown here:

    Add-PrinterPort -Name 'bogus:' -PrinterHostAddress '10.10.10.10'

    The command and the output from Get-PrinterPort are shown in the following image.

    Image of command output

    Deleting the printer port

    When I create something via Windows PowerShell, I also always like to know how to clean it up. To delete a printer port, I use the Remove-PrinterPort function. The use of the Remove-PrinterPort function is shown here:

    Get-PrinterPort | Where name -eq 'bogus:' | Remove-PrinterPort

    The following image shows the command and its associated output.

    Image of command output

    That is all there is to using Windows PowerShell to create new printer ports. Printer Week will continue tomorrow when I will talk about installing printer drivers.

    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 Get Printer Configuration

    Summary: Use Windows PowerShell in Windows 8 to find your printer configurations.

    Hey, Scripting Guy! Question How can I use Windows PowerShell in Windows 8 to get the printer configuration of all printers?

    Hey, Scripting Guy! Answer Use the Get-Printer function, and  pipe it to Foreach-Object and the Get-PrinterConfiguration cmdlet:

    Get-Printer | ForEach {Get-PrintConfiguration $_.name}

  • Install Printer Drivers with PowerShell in Windows 8

    Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell in Windows 8 to install printer drivers.

    Microsoft Scripting Guy, Ed Wilson, is here. This morning, it is rainy and overcast here in Charlotte, North Carolina, but it is pleasantly cool. The Scripting Wife migrated to the lanai and is sitting on her swing and checking Facebook on her Windows RT Surface. I am in my office checking email sent to scripter@microsoft.com. I am sipping a cup of English Breakfast tea with a cinnamon stick, lemon grass, hibiscus blossom, orange peel, and a bit of spearmint. It is a very refreshing cup of tea.

    When it comes to using Windows PowerShell to install print drivers, there is the long way and the short way. The long way is…well…long and rather complicated. The short way is easy. The difference in the two methods is not necessarily a conscious choice, but rather a function of the drivers already installed in Windows and the print device you intend to hook up.

    For example, we all know that Windows ships with a whole bunch of printer drivers already on the disk. They reside in the Windows\inf folder, and they all begin with the letters prn. The following script lists the printer drivers that ship with Windows.

    Get-ChildItem ((Get-Item Env:\systemroot).value+"\inf") -Exclude *.pnf -recurse |

    Where-Object { $_.name -match "prn" } |

    Sort-Object -Property name |

    format-table -Property name, length, creationTime, lastWriteTime -AutoSize

    Of course, one issue is a bit convoluted. The following image illustrates the output.

    Image of command output

    The issue is that the names, such as prnbrcl1.inf, do not make too much sense. I can go to the Windows/inf directory, and open the .inf file in Notepad, and I am greeting with something that looks like the following.

    Image of file content

    If I compare this output with the output from the advanced printer installation dialog box, I can see similarities. This is shown here.

    Image of menu

    If I select a printer driver from the previous list, and click Next, the driver installs. I can verify this via the Get-PrinterDriver function, as shown here:

    Get-PrinterDriver

    The following image shows the command and its output.

    Image of command output

    I can then use the Get-PrinterDriver function to retrieve the newly installed printer:

    Get-PrinterDriver -Name "Brother *"

    If I attempt to remove it, however, an error message appears, which states that it is being used by a printer. This command and the error message are shown here.

    Image of error message

    After I remove the printer that uses the driver, I can then remove the printer—but that is tomorrow’s blog post.

    To add a printer driver that exists in the driver store, I need to use the actual driver name. I cannot use wildcard characters, or an error message appears. For example to install the "Brother Laser Leg Type1 Class Driver" that I found in the .inf files, I must use the complete name. This command is shown here:

    Add-PrinterDriver -Name "Brother Laser Leg Type1 Class Driver"

    If I attempt to use Brother *, an error occurs. This message is shown in the following image.

    Image of error message

    I can also use the Add-PrinterDriver function to install a print driver by specifying the name of the .inf file for that printer driver. One issue is that often printer drivers are “universal drivers,” and the .inf file contains information for dozens of printers. Therefore, Windows PowerShell will not know which driver to install.

    That is all there is to using Windows PowerShell to install printer drivers. Printer week will continue tomorrow when I will talk about removing printers.

    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 Display Help for Module Cmdlets

    Summary: Use Windows PowerShell to display all Help for all cmdlets in a module.

    Hey, Scripting Guy! Question How can I see all of the Help examples for cmdlets from a specific module?

    Hey, Scripting Guy! Answer After you have updated your Help in Windows PowerShell 3.0, use the Get-Command cmdlet to retrieve all cmdlets from a specific module, pipe the results to the Foreach-Object cmdlet, and use the Get-Help cmdlet inside the script block. Following is an example for the PrintManagement module:

    Get-Command -Module PrintManagement| Foreach-Object {get-help $_.name -Examples}

    Here is a shorter version of the same command:

    gcm -mo *print* | % {get-help $_.name -ex}

  • Use PowerShell in Windows 8 to Remove Printers

    Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell 3.0 in Windows 8 to remove printers.

    Microsoft Scripting Guy, Ed Wilson, is here. The Scripting Wife and I have been talking to various people from the Charlotte Windows PowerShell User Group all week about doing another Windows PowerShell Saturday. It is an awful lot of work, but I think we are going to do this again. The Windows PowerShell Saturday in Charlotte sold out within a few days, and there have been many positive comments about the event. That means that people found it to be a valuable experience. So we will have another Windows PowerShell Saturday. (By the way, if you want to have one where you live, let us know via scripter@microsoft.com.)

    To remove a printer with Windows PowerShell, I use the Remove-Printer function from the PrinterManagement module. There are two ways to use the Remove-Printer function:

    Remove-Printer [-Name] <String> [-AsJob [<SwitchParameter>]] [-CimSession

    <CimSession>] [-ComputerName <String>] [-PassThru [<SwitchParameter>]]

    [-ThrottleLimit <Int32>] [-Confirm [<SwitchParameter>]] [-WhatIf

    [<SwitchParameter>]] [<CommonParameters>]

     

    Remove-Printer [-AsJob [<SwitchParameter>]] [-CimSession <CimSession>]

    [-PassThru [<SwitchParameter>]] [-ThrottleLimit <Int32>] -InputObject

    <CimInstance> [-Confirm [<SwitchParameter>]] [-WhatIf [<SwitchParameter>]]

    [<CommonParameters>]

    What this means is that if I type the exact printer name, I can use the Remove-Printer function directly. It also tells me that I can pipe a printer object to the function. By pipelining a printer object, I can use wildcard characters.

    Begin with Get-Printer

    I usually begin things by using a Get type of command. So the first thing I do is use the Get-Printer function to see what printers are defined. The command is shown here:

    Get-Printer

    The command and its associated output are shown here:

    Image of command output

    I can use a wildcard character to avoid typing a complete printer name as shown here:

    PS C:\> Get-Printer | where name -Like "my*"

     

    Name                           ComputerName    Type         DriverName

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

    myotherlaser                                   Local        Brother Laser Leg Typ...

    Or, I can type the exact printer name and supply it directly to the –Name parameter as shown here:

    PS C:\> Get-Printer -Name myotherlaser

     

    Name                           ComputerName    Type         DriverName

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

    myotherlaser                                   Local        Brother Laser Leg Typ...

    Both of these commands return printer objects, and therefore, they can be piped to the Remove-Printer function. This is shown here:

    Get-Printer -Name myotherlaser | Remove-Printer

    Get-Printer | where name -like "my*" | Remove-Printer

    Remember Whatif

    Of course, before I add a Remove-Printer object, I want to use the –Whatif switch to ensure that I am doing exactly what I want to do. Here is an example of a near disaster:

    PS C:\> Get-Printer | where name -match "my*" | Remove-Printer -WhatIf

    What if: Deleting printer Microsoft XPS Document Writer

    What if: Deleting printer \\dc1.iammred.net\HP LaserJet 2100 PCL6

    What if: Deleting printer myotherlaser

    PS C:\>

    Luckily, I used –Whatif, so I did not delete a bunch of my printers.

    Directly remove a printer

    I can use the Remove-Printer function directly to remove a printer if I know the exact name. If I am unsure of the printer name, I use the Get-Printer function to list my printers, and I copy and paste the name. With quick edit mode turned on, I can highlight the printer name with my mouse, press ENTER to copy it to the clipboard, and then right-click to paste it. This is shown in the image that follows.

    Image of command output

    Here is the command:

    Remove-Printer -Name myotherlaser

    After I have deleted the printer, I may decide to delete the printer driver and the printer port (if necessary). To do that, I use the following functions:

    PS C:\> Get-PrinterDriver -Name "Brother*"

     

    Name                                PrinterEnvironment MajorVersion    Manufacturer

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

    Brother Laser Leg Type1 Class Dr... Windows x64        4               Brother

     

    PS C:\> Get-PrinterDriver -Name "Brother*" | Remove-PrinterDriver

    I use the Get-PrinterPort function, and I decide that I do not need to remove any printer ports.

    That is all there is to using Windows PowerShell to remove printers. This also concludes Printer Week. Join me tomorrow when I will talk about running scripts on remote file shares.

    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 Rename Printers

    Summary: Learn how to use Windows PowerShell 3.0 in Windows 8 to rename a printer.

    Hey, Scripting Guy! Question How can I use Windows PowerShell 3.0 in Windows 8 to rename a printer?

    Hey, Scripting Guy! Answer Use the Get-Printer function to retrieve the printer, and pipe it to the Rename-Printer function:

    Get-Printer -Name 'mynewlaser' | Rename-Printer -NewName 'myotherlaser'

  • Running PowerShell Scripts from a Remote File Share

    Summary: Microsoft Scripting Guy, Ed Wilson, talks about running Windows PowerShell scripts from a remote file share.

    Microsoft Scripting Guy, Ed Wilson, is here. It is sort of official…

    There are at least three Windows PowerShell Saturday events coming up. They are listed on the PowerShell Saturday website. Atlanta and Singapore are already planning (I know, because I will be speaking at both events). The Charlotte event is still early in the planning stages (I will be speaking there also). Of course, don’t just take my word for it. Bookmark the PowerShellSaturday website, so you can keep up to date on all the events.

    First things first

    Note  For good background info about running Windows PowerShell scripts from a remote file share, check out the guest blog post written by June Blender and Judith Herman: How to Run PowerShell Scripts from a Shared Directory.

    So I have this shared folder on one of my servers. I can open Windows PowerShell and use the Net View command to see all of the shares. I can then use the Get-ChildItem command (dir is an alias) to view the files in the shared folder. This is shown here.

    Image of command output

    If I want to look at the files in a GUI, I can type the path into Internet Explorer, and view the files in the File Explorer as shown in the following image.

    Image of menu

    For a background, I happen to know that the remote server is running 32-bit Windows Server 2008. I also found out that the server is running Windows PowerShell 2.0. I did this by using the Invoke-Command cmdlet (icm is an alias) as shown here:

    PS C:\> icm -ComputerName dc1 {$PSVersionTable}

    Name                           Value

    ----                           -----

    PSRemotingProtocolVersion      2.1

    BuildVersion                   6.0.6002.18111

    PSCompatibleVersions           {1.0, 2.0}

    PSVersion                      2.0

    CLRVersion                     2.0.50727.4241

    WSManStackVersion              2.0

    SerializationVersion           1.1.0.1

    Open script in ISE

    The cool thing is that I can open a Windows PowerShell script in the Windows PowerShell ISE on my 64-bit laptop (running Windows 8a and Windows PowerShell 3.0) from the remote file share. So I do the following:

    • I open the Windows PowerShell ISE.
    • I click File, then Open.
    • In the Open dialog box, I type the UNC path to the remote file share and I press ENTER. I am now viewing the files from the share, as shown in the following image.

    Image of menu

    I view (and edit if required) the script from the remote file share. When I am ready, I click the green triangle (or press F5) to run the script. At the top of the output pane, I see the UNC location to the script. On the subsequent lines, I see the output.

    Keep in mind that the script resides on a remote file share, but the execution of the script takes place on my local computer, and the output that is displayed relates to my local computer. For instance, the remote server is a Dell device, but my local laptop is a Lenovo device. The remote server is named DC1, but my local laptop is named EDLT. The script and the output from the script are shown here.

    Image of command output

    Run directly in the Windows PowerShell console

    But I do not need to open the script in the Windows PowerShell ISE; instead, I can run it directly from the Windows PowerShell console. Two ways to do this are to dot-source the script, or to use the Invocation operator.

    PS C:\> . \\dc1\share\ServerNameBios.ps1

    PS C:\> & \\dc1\share\ServerNameBios.ps1

    The commands and the output from the commands are shown in the following image.

    Image of command output

    That is all there is to using a Windows PowerShell script from a remote file share. Join me tomorrow when I will talk about more stuff related to running a script from a remote file share.

    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 Get DHCP Stats

    Summary: Learn how to use Windows PowerShell 3.0 in Windows Server 2012 to get DHCP statistics.

    Hey, Scripting Guy! Question How can I get an overview from my DHCP server running on Windows Server 2012?

    Hey, Scripting Guy! Answer Use the Get-DHCPServerv4Statistics function:

    Get-DhcpServerv4Statistics -ComputerName DHCP1

  • Weekend Scripter: Run PowerShell Scripts from Remote File Share: Part 2

    Weekend Scripter: Run PowerShell Scripts from Remote File Share: Part 2

    Summary: Microsoft Scripting Guy, Ed Wilson, continues his discussion about running scripts on a remote file share.

    Microsoft Scripting Guy, Ed Wilson, is here. This week has been absolutely bizarre. I have been really busy working with a select group of Honorary Scripting Guys for upcoming blog posts. I must say, there is some absolutely way cool, knock-out stuff in the works. But of course, to make all of this streamlined, I had to set up a shared Office 365 SharePoint site, grant permissions, create views, test things out, and all of that. You know what? Dude, it was easy!!! As you may guess from the three exclamation points, I was surprised. I must say that I was dreading it. I will also say that it was so intuitive that I did not once have to use Help or search for How-To articles. It really makes sense, and it has actually been a fun project. As one twentieth-century philosopher said, “I love it when a plan comes together.”

    Examining script execution policy

    Note  This is the second in a multipart series of posts. The first post was Running Scripts from a Remote File Share. For good background info about running Windows PowerShell scripts from a remote file share, check out the guest blog post written by June Blender and Judith Herman: How to Run PowerShell Scripts from a Shared Directory.

    By default when you open Windows PowerShell, the execution of scripts is disabled. This is because the default script execution policy in Windows PowerShell is restricted. To see the current script execution policy, use the Get-ExecutionPolicy cmdlet. For the current user, all you need to do is type the cmdlet name. This is shown here:

    PS C:\> Get-ExecutionPolicy

    RemoteSigned

    To see all of the execution policies, use the –List switch as shown here:

    PS C:\> Get-ExecutionPolicy -List

     

                                 Scope                           ExecutionPolicy

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

                                 MachinePolicy                   Undefined

                                 UserPolicy                         Undefined

                                 Process                             Undefined

                                 CurrentUser                       RemoteSigned

                                 LocalMachine                     Unrestricted

    You can see that there are multiple levels to which the script execution policy can be set. An ordinary user can change the CurrentUser script execution policy (unless it is specified via Group Policy. In that case, it cannot be modified by a local user). When the execution policy is first checked, it is restricted; therefore, no scripts will run. In the following example, the execution policy is set to RemoteSigned for the current user, and a check verifies that the change works.

    Image of command output

    What is RemoteSigned, anyway?

    A good setting to use in an enterprise situation is RemoteSigned. This means that a script from a remote location must be signed by a recognized Certification Authority (CA) with a code-signing certificate. There are specific trusted roots that are set up automatically. I can see them by using the Cert PS: drive and looking at CurrentUser\Root. The command is shown here:

    dir Cert:\CurrentUser\Root

    The following image shows the command and output from the command.

    Image of command output

    So, if a script runs from a remote location, it must be signed by one of the CAs with a root listed in the previous output. I can use Group Policy to add a trusted CA, so I can issue code-signing certificates on my local network. I can also purchase a code-signing certificate from the Internet and if it is trusted, everything will be groovy. But I only need to do that if the location is remote.

    Note  Refer to the post listed earlier by Judith and by June for more information about this.

    Because Windows PowerShell relies on the Internet Explorer definition of what is remote, a network share on my home domain is considered remote. Therefore, it needs to be signed. But more than that, even if I set my execution policy to Unrestricted, it STILL will prompt prior to running. This is by design, but it can be annoying. The best way to modify the Internet Explorer trusted sites setting is to use Group Policy. This is shown here:

    Image of menu

    In my mind, the best way to do this via Group Policy is to create a special Group Policy Object (GPO) with this setting and then apply it to appropriate scope within the domain. Give it a nice name so it makes it easy to keep up with.

    After I have made my changes—even with RemoteSigned as the execution policy—I can run my scripts from network shares. This is because the network shares are not considered remote. This is shown here.

    Image of command output

    Well, that is about it for today. I am going to head out to my woodworking shop and work on my hand-cut dovetails. Join me tomorrow when I will continue this discussion about remotely running scripts from file shares.

    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: Change PowerShell Script Execution Policy

    Summary: Learn how a user can change the Windows PowerShell script execution policy.

    Hey, Scripting Guy! Question How can I change the Windows PowerShell script execution policy as simply an ordinary user?

    Hey, Scripting Guy! Answer Use the –Scope parameter with the Set-ExecutionPolicy cmdlet and specify CurrentUser (the –Force parameter hides prompts from the cmdlet):

    Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force

  • Weekend Scripter: Run PowerShell Scripts from Remote File Share: Part 3

    Summary: Microsoft Scripting Guy, Ed Wilson, continues his discussion about running scripts from a remote file share.

    Microsoft Scripting Guy, Ed Wilson, is here. Some things should just be easier. For example, I should have access to client-side cmdlets to work with SharePoint. Many times, as a user, I need to accomplish repetitive tasks, and a few cmdlets could really come in handy. Running scripts from remote file shares should be easier as well.

    Easier? What am I talking about? Well when someone asks a question, there are so many “it depends,” “maybe,” and “whatever” stuff going on that it really makes what should be easy very complicated. For example, in a freshly created Windows Server 2012 forest, I created a share on the domain controller. I modified the script execution policy on the client, and I could run scripts from the share just fine. No configuration, no signing, no nothing. It just worked. But to make a proclamation would take hours of testing in all different sorts of variables.

    The easy way to run a script

    Note  This is the third in a multipart series of posts. The first post was Running Scripts from a Remote File Share. The second post was Weekend Scripter: Run PowerShell Scripts from Remote File Share: Part 2. For good background info about running Windows PowerShell scripts from a remote file share, check out the guest blog post written by June Blender and Judith Herman: How to Run PowerShell Scripts from a Shared Directory.

    The easy way to run a script from a remote file share is to use the Bypass methodology. This is not a security hole, because the script execution policy and the associated settings are not really security features—they are a security convenience. This means that they are in place to remind me to do the right thing—to encourage me to follow best practices. But they are not put in place to discourage getting the job done.

    So, all the discussion about the script execution policy and signed scripts can be bypassed if I need to do so. What is a common requirement? Well, running a script from a scheduled task, or from within a Group Policy Object. If the desktop and network configuration are complicated to the point of not knowing what will go on, I can use Bypass mode and still get my scripts to run.

    To illustrate this point, I change my script execution policy to Restricted. This is the way it comes out of the box. Scripts do not run.

    Image of error message

    Using Bypass mode

    So, if I want to run a script in Bypass mode, I can use the Run dialog box. One problem I have with the Run dialog box is that it is very small, and it does not resize. The Run box is shown here:

    Image of dialog box

    So, what I like to do is open Notepad, compose my command, and then paste it into the run dialog box. There are a couple of things that are important to the command. First, I add –NoExit. From a scheduled task, I would not do this. I would, instead, have my script output to a log file. I added –NoExit so that I could see the output. The key to making this work is specifying the –ExecutionPolicy parameter of Bypass. I then provide the UNC path to the script that I want to run. I would use this exact sort of syntax (without the NoExit) to run a script from a scheduled task.  Here is my command:

    powershell -noexit -executionpolicy bypass -file \\dc1\Share\ServerNameBios.ps1

    Here is the command in Notepad:

    Image of command

    When the command runs, it opens a new instance of Windows PowerShell, executes the script, and displays the output from the script. The execution policy of the newly created instance of Windows PowerShell is Bypass. This is shown in the following image.

    Image of command output

    Well, that is it for today. I am heading outside, so have a great day, and join me tomorrow as I begin Active Directory Domain Services Migration Week.

    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 Report Network Adapter Binding

    Summary: Use Windows PowerShell 3.0 in Windows 8 to view network adapter binding information.

    Hey, Scripting Guy! Question How can I use Windows PowerShell 3.0 in Windows 8 to review network adapter binding information?

    Hey, Scripting Guy! Answer Use the Get-NetAdapterBinding function and pipe the resulting information to the Format-List cmdlet:

    Get-NetAdapterBinding | Format-List *

  • Adding Office Locations in AD DS with PowerShell

    Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to add office locations in Active Directory Domain Services.

    Hey, Scripting Guy! Question Hey, Scripting Guy! We are in the midst of a domain migration at work, and I need to clean up a number of attributes in Active Directory prior to our migration. Part of our issue is that we have attributes that are missing values, and I just hate to migrate empty stuff. Is there anything you can do to help?

    —TV

    Hey, Scripting Guy! Answer Hello TV,

    Microsoft Scripting Guy, Ed Wilson, is here. I am listening to my customized Internet radio station with a cool app I found for Windows 8 in the Windows Store. It is really cool to be able to select my listening preferences. I have actually spent a bit of time and created a couple of special Scripting Guy stations. It all depends on what I am writing. For example, Active Directory Domain Services questions simply beg for a bit of classic New Orleans style jazz—or, that is just me. Jazz also goes well with spearmint, wintergreen, peppermint, and lemon grass with a spoon full of Gun Powder Green tea. So I have my tunes and my tea. I guess I will answer your question.

    First find the attribute

    The first thing I need to do is to find the attribute that is missing. I first look at the user in Active Directory Users and Computers. This is shown here:

    Image of menu

    It seems that the Office attribute is missing from all of the user objects. I add a bunch of AAAAAs to the Office field so I can find the attribute in ADSI Edit. I check with ADSI Edit, and sure enough the Office attribute is named physicalDeliveryOfficeName as shown in the following image. Good, that makes it easy. 

    Image of menu

    I look around, and all of the cities are populated. So I check ADSI Edit, and I figure out that it uses a lower-case las in L for Location. This is shown here.

    Image of menu

    Populating the Office field

    In my example, the office names are the same as the city names. So all I need to do is to read all of the city names from all users in the TestOU organizational unit and add the city value to the Office attribute. First, let me make sure I can get the cities for all users. This is shown here:

    Get-ADUser -Filter * -SearchBase 'ou=testou,dc=iammred,dc=net' -Properties l

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

    Image of command output

    As it turns out, I do not need to know the physicalDeliveryOfficeName attribute name because Set-ADUser has an –Office parameter. I compose the following command and use the –Whatif parameter to ensure that things will do what I want them to do.

    PS C:\> Get-ADUser -Filter * -SearchBase 'ou=testou,dc=iammred,dc=net' -Properties l

    | Foreach {Set-ADUser $_ -Office $_.l -whatif}

    The command and the output are shown here.

    Image of command output

    So, I remove the –Whatif and run the command again. This time, nothing returns from the command. (On my system, it takes about five seconds to run.) Here is the command (this is a one-line command broken at the pipe for readability):

    Get-ADUser -Filter * -SearchBase 'ou=testou,dc=iammred,dc=net' -Properties l|

     Foreach {Set-ADUser $_ -Office $_.l}

    I use Active Directory Users and Computers and check a few users. Here is the first user. The command worked.

    Image of menu

    TV, that is all there is to using Windows PowerShell to add office locations to users in a specific AD DS OU. Active Directory Domain Services Week will continue tomorrow when I will talk about Active Directrory migration cleanup.

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

    Ed Wilson, Microsoft Scripting Guy 

  • PowerTip: Use PowerShell to See Network Adapters Bound to TCP/IP

    Summary: Use Windows PowerShell 3.0 in Windows 8 to see network adapters that are bound to TCP/IP.

    Hey, Scripting Guy! Question How can I find all network adapters that are bound to TCP/IPv4 by using Windows PowerShell 3.0 in Windows 8?

    Hey, Scripting Guy! Answer Use the Get-NetAdapterBinding function, pipe the results to a Where-Object cmdlet, and filter for the BindName equal to ‘tcpip’:

    Get-NetAdapterBinding | where bindname -eq 'tcpip'

  • Add User Principal Names in Active Directory via PowerShell

    Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use Windows PowerShell to add user principal names to users in Active Directory.

    Hey, Scripting Guy! Question Hey, Scripting Guy! We are planning for our Active Directory migration, and as part of that, I am reviewing users. The problem is that I found out that whoever set up our original installation did not assign values for user principal names (UPN). This will cause us a problem as we move to a federated environment. Can you offer an easy way to populate this value?

    —CG

    Hey, Scripting Guy! Answer Hello CG,

    Microsoft Scripting Guy, Ed Wilson, is here. This morning I am sitting on our lanai and checking my scripter@microsoft.com email on my Microsoft Surface RT. I received an email from one of my friends in Hawaii. He was telling me about a Hukilau he went to over the weekend. From his description, it makes me want to grab the Scripting Wife and head out west on the next available flight. The big problem right now, is the weather. I prefer August in Australia to August in Hawaii—it is really hot there.

    In Active Directory Users and Computers, the UPN shows up as the user logon name. It displays the UPN in two different fields, as shown in the following image.

    Image of menu

    To find the actual Active Directory attribute name, I add a bunch of AAAs to the user logon name, and select a domain from the drop-down list. I then go into ADSI edit and look up the value. I see the following:

    Image of menu

    Searching for existing values

    I use the Get-ADUser cmdlet to look for existing values for the UserPrincipalName attribute. To find the value of the UserPrincipalName attribute, I have to specify it for the –Properties parameter. I specify the SearchBase of the organizational unit (OU), and I use the * filter. This is shown here:

    Get-ADUser -Filter * -SearchBase 'ou=testou,dc=iammred,dc=net' -Properties userPrincipalName

    The command and associated output are represented in the following image.

    Image of command output

    Setting the UPN value

    I use the Get-ADUser cmdlet to retrieve all the users to set. I pipe the resulting user objects to the Foreach-Object cmdlet, and in the script block, I use the Set-ADUser cmdlet. The Set-ADUser cmdlet has a –userPrincipalName parameter that makes it easy to set the UPN.

    To create the UPN, I use a hardcoded domain name, and I get the user’s name from the Name attribute. I use parameter substitution and the –f format specifier to concatenate the user principal name. The command is shown here (this is a single-line command that I broke at the pipe for readability):

    Get-ADUser -Filter * -SearchBase 'ou=testou,dc=iammred,dc=net' -Properties userPrincipalName | foreach { Set-ADUser $_ -UserPrincipalName ("{0}.{1}" -f $_.name,"iammred.net")}

    CG, that is all there is to using Windows PowerShell to add the UPN for user accounts. Active Directory Week will continue 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: Use PowerShell to Get DHCP Server Database Info

    Summary: Learn how to use Windows PowerShell to get the DHCP Server database information.

    Hey, Scripting Guy! Question How can I use Windows PowerShell to get the database information for a DHCP server if I do not know the name of the server?

    Hey, Scripting Guy! Answer Use the ServerName property from the object returned by Get-DHCPServer to get the computer name, then use the Get-DhcpServerDatabase:

    Get-DhcpServerDatabase -ComputerName (Get-DhcpServer).ServerName

    Note   The DHCP functions come from the DHCPServer module obtained via the RSAT tools for Windows Server 2012. 

  • Use PowerShell to Change Sign-in Script and Profile Path

    Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to modify the sign-in script and profile path in Active Directory.

    Hey, Scripting Guy! We are in the middle of an Active Directory migration (primarily moving our client computers from Windows XP to Windows 8). We are also consolidating our file servers and our profile servers. We have multiple sites, and in the past, each site had a one or more domain controllers, multiple file and print servers, and other stuff as needed.

    Now, we are collapsing that infrastructure into a single server running Hyper-V. Needless to say, our profiles will be moving to different servers, and we will also be changing our sign-in scripts. So I need an easy way to modify these settings for our users. The new servers will be based on the user’s city locations. Can you help?

    —RA

    Hello RA,

    Microsoft Scripting Guy, Ed Wilson, is here. Things have been busy around the Scripting House. I got up early to check the scripter@microsoft.com email and to write a couple of proposals for Windows PowerShell Saturday in Atlanta. According to Mark, I will be making two presentations—one for the beginner track and one for the advanced track. In addition, I have been working on my presentation that I will be conducting remotely for Windows PowerShell Saturday in Singapore.

    Find the attribute names

    The first thing we need to do is to find the ADSI attribute names for the profile path and for the sign-in script. I open up one of the user profiles and type some bogus information so that I can find the attributes in ADSI Edit. Here is the page from Active Directory Users and Computers:

    Image of menu

    Now I navigate to the same user object in ADSI Edit and look up the ADSI property names. The names make sense: ProfilePath and ScriptPath. This is shown here:

    Image of menu

    Get the information from AD DS

    Now I need to retrieve the information from Active Directory Domain Services (AD DS). I could do all this from inside the Windows PowerShell console, but I decided to use the Windows PowerShell ISE instead. It has better intellisense, and for something like this, it makes things a bit more readable. I decide to use a couple of variables to hold the organizational unit (OU) and the properties that I need to retrieve. I then use Get-ADUser to retrieve the information. Here is this portion of the script:

    Import-Module ActiveDirectory

    $ou = "OU=Testou,Dc=Iammred,Dc=Net"

    $properties = "ProfilePath","ScriptPath", "l"

    Get-ADUser -Filter * -SearchBase $ou -Properties $properties

    I can highlight only this section of the script to test it. After I see that it works, I pipe the returned information to the Foreach-Object cmdlet. The hardest part of the script is to create the profile path and the script path. I decide to use parameter substitution and the Format operator to do this because, for me anyway, it is easier to read.

    I build the profile path based on the city name. I then add Storage1 (which is the name of the storage server) and Profiles (which is the name of the folder that holds the profiles). Next, I use the user’s SamAccountName attribute. Here is the string:

    $ProfilePath = "{0}\storage1\profiles\{1}" -f $_.l, $_.SamAccountName

    Now, to create the script path. To do that, I again use the city name. I also store the scripts in Storage1, and I place them in a folder named Scripts. The sign-in script is based on the city name and the word LogonScript. Therefore, I am only substituting a single word: the city name, which is the l attribute. Here is the string I use for this:

    $ScriptPath = "{0}\storage1\scripts\{0}_logonScript.ps1" -f $_.l

    The rest is really easy. All I need to do is to use the Set-ADUser cmdlet to plug in the values. Here is that command:

    Set-ADUser $_.samaccountname -ProfilePath $ProfilePath -ScriptPath $ScriptPath

    The complete script is shown here:

    Import-Module ActiveDirectory

    $ou = "OU=Testou,Dc=Iammred,Dc=Net"

    $properties = "ProfilePath","ScriptPath", "l"

    Get-ADUser -Filter * -SearchBase $ou -Properties $properties |

    ForEach-Object {

     $ProfilePath = "{0}\storage1\profiles\{1}" -f $_.l, $_.SamAccountName

     $ScriptPath = "{0}\storage1\scripts\{0}_logonScript.ps1" -f $_.l

     Set-ADUser $_.samaccountname -ProfilePath $ProfilePath -ScriptPath $ScriptPath

    }

    When I run the script, nothing returns. But that is what I want (I really do not want a whole bunch of errors). Here is the ISE and the blank output from running the script:

    Image of command output

    I check Active Directory Users and computers to ensure that everything worked as planned. It is fine, as shown here:

    Image of command output

    RA, that is all there is to using Windows PowerShell to create values for the sign-in script and the profile path. Active Directory Week will continue tomorrow when I will talk about logging an attribute change.

    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 Display Replications in AD DS

    Summary: Use Windows PowerShell to display replication connections in Active Directory Domain Services.

    Hey, Scripting Guy! Question How can I use a cmdlet from the Active Directory module to display replication connections in AD DS?

    Hey, Scripting Guy! Answer Use the Get-ADReplicationConnection cmdlet and select the ReplicateFromDirectoryServer property and the ReplicateToDirectoryServer property (this is a single-line command broken at the pipe character for readability):

    Get-ADReplicationConnection |

    select ReplicateFromDirectoryServer, ReplicateToDirectoryServer 

  • Use PowerShell to Log Changes to AD DS Attributes

    Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to log changes made to Active Directory Domain Services attribute values.

    Hey, Scripting Guy! Question Hey, Scripting Guy! We are in the process of merging a couple of resource domains, and we need to modify some user accounts prior to the move. I have been tasked with making the changes, and I plan to use Windows PowerShell to perform the actual work. I need to create before and after logs. The before log shows the value of the attributes that I am going to change prior to running the script, and the after log will show the value of the attributes after running the script. Can you show me how I might go about doing this? Thanks, Scripting Guy, you are the best!

    —CX

    Hey, Scripting Guy! Answer Hello CX,

    Microsoft Scripting Guy, Ed Wilson, is here. This morning I am sitting on the lanai, and sipping a cup of English Breakfast tea. I put a bit of lemon grass, hibiscus flower, rose hips, spearmint, and a cinnamon stick in the tea. The flowers give it a citrus flavor, and the mint makes it very refreshing. The trick is that I only let it steep for three minutes, and that keeps it from becoming too bitter. It took me several tries to get this one just right. Because it is pretty early, it is not too hot or humid outside yet. I have my Surface RT, and am checking my scripter@microsoft.com email.

    So, CX, you did not specify how you want your logging to take place, but I decided that exporting to a CSV file would work out well. Then you could import it into Microsoft Excel if you want to do so.

    Finding the attribute and values

    The first thing to do is to create a little script that will populate an attribute with before values. I am going to populate the Post Office Box attribute, so I need to look it up in ADSI edit. I come up with the following (surprisingly, it is named postOfficeBox):

    Image of menu

    I write a little script to add values to this attribute. Here is the script:

    Import-Module activeDirectory

    $ou = "ou=testou,dc=iammred,dc=net"

    $i = 1

    Get-ADUser -Filter * -SearchBase $ou |

    ForEach-Object {

    Set-ADUser $_ -POBox "Post Office Box $i"

    $i++ }

    Now I want to see how many different cities are represented by the users in the organizational unit (OU). I modify my script a bit and use the –Unique parameter from the Select-Object command. This is shown here:

    Get-ADUser -Filter * -SearchBase $ou -properties $properties | select l -Unique

    The following output tells me that I have three cities:                                                                                                         

    Atlanta                                                                                                    

    Charlotte                                                                                                   

    Jacksonville  

    Therefore, I need to add a bit of logic to detect the city. If the city is Atlanta, I will set the postOfficeBox attribute to 222; if it is Charlotte, I will set it to 333; and if it is Jacksonville, I will set it to 444.

    Making the changes

    The first thing I do is use the Get-ADUser cmdlet to return the user name and the postOfficeBox attribute. I use the Select-Object cmdlet to get these two attributes, and I pipe the output to Export-CSV. No problem…until I open the spreadsheet in Excel. Here is the results:

    Image of spreadsheet

    The issue is that for some reason, the postOfficeBox attribute is a collection. I therefore modify my script a bit, and I select the first PO Box. Here is the script:

    Import-Module activeDirectory

    $ou = "ou=testou,dc=iammred,dc=net"

    $Before = "c:\fso\before.csv"

     

    $properties = "PostOfficeBox"

    Get-ADUser -Filter * -SearchBase $ou -properties $properties |

    Select name, @{L='pobox';E={$_.postofficebox[0]}} |

    Export-Csv -Path $before -NoTypeInformation -Force

    Now I open the script in Excel, and it appears like I expected:

    Image of spreadsheet

    So now I use the Get-ADUser cmdlet to retrieve my user objects. I pipe everything to a Foreach-Object cmdlet, and I use a Switch statement inside the Foreach-Object. I read a Switch statement like a series of If statements, for example: If the city matches Atlanta, then I set the POBox variable to 222.

    I then use the Set-ADUser cmdlet inside the Foreach-Object cmdlet to make the actual changes. Here is the script:

    Import-Module activeDirectory

    $ou = "ou=testou,dc=iammred,dc=net"

    $properties = "l","PostOfficeBox"

    Get-ADUser -Filter * -SearchBase $ou -properties $properties |

    ForEach-Object {

     Switch ($_.l)

     { "Atlanta" {$pobox = "POBox 222"}

       "Charlotte" {$pobox = "POBox 333"}

       "Jacksonville" {$pobox = "POBox 444"} }

    Set-ADUser $_ -POBox $pobox

    }

    Now I run my documentation script again and open the Excel spreadsheet. I can see that the changes took place as expected. Cool.

    Image of spreadsheet

    CX, that is all there is to using Windows PowerShell to make changes to AD DS attribute values and to log the changes. Active Directory Week will continue tomorrow when I will talk about different ways of working with Active Directory.

    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 Show Approved Verbs Group

    Summary: Use Windows PowerShell to show the group of approved Windows PowerShell verbs.

    Hey, Scripting Guy! Question How can I find the grouping information for a couple of approved verbs that I want to use to name my advanced functions?

    Hey, Scripting Guy! Answer Use the Get-Verb function, and supply an array of verbs to the function:

    get-verb ping, receive

     

  • Use PowerShell to Customize Server Manager

    Summary: Guest blogger, Rolf Masuch, talks about using Windows PowerShell to customize Server Manager.

    Microsoft Scripting Guy, Ed Wilson, is here. Today we have a guest post written by Rolf Masuch, who is a senior consultant for Microsoft in Germany. Today is Rolf’s birthday, and he wanted to start the celebration off right by sharing a couple of cool scripts with us. Take it away Rolf…

    When it comes to the new versions of Windows Server 2012 R2 and Windows Server 2012, one of my most-loved changes is to Server Manager. The new Server Manager Dashboard looks like this:

    Image of menu

    Lots of documents have been written already about this new way of working. Today I’d like to share two extension scripts that I thought would be helpful for the community because when it comes to automating Server Manager, you cannot do two things:

    1. Add servers to your list of managed servers
    2. Create groups that contain a custom list of servers

    You will find the respective menu entries in Server Manager when you click Manage.

    Image of menu

    But first, let’s look behind the curtain of Server Manager. It stores information in an XML file that is saved per user at this location:

    $ENV:APPDATA\Microsoft\Windows\ServerManager\ServerList.xml

    Additionally, it is useful to know that every time you close a running Server Manager instance, it can overwrite your scripted changes. We want to take care that before we make changes to the XML file, we close the Server Manager process. We also need to make all changes in an elevated process.

    When it comes down to writing additional entries to the file, you may think, “Hey, it is just XML, this is easy.” But when you look at the structure of the XML file, you see that this is not so simple. The following example is from a freshly installed system with one additional group:

    ServerManager.xml

    ***

    <?xml version="1.0" encoding="utf-8"?>

    <ServerList xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" localhostName="MyCloudComp001" xmlns="urn:serverpool-schema">

    <ServerInfo name="MyCloudComp001" status="1" lastUpdateTime="2013-08-08T09:01:26.7659233+00:00" locale="en-US" /><ServerGroupInfo id="3" name="MyGroup" />

    <ServerGroupMembership server="MyCloudComp001" serverGroupId="3" />

    </ServerList>

    ***

    As you see from the initial lines, the XML structure is using an additional namespace that is named urn:serverpool-schema. When you want to add new elements to this structure, you need to take care of that. So how is it done?

    Let’s look at the script Add-ServerToManagedServerList.ps1. Here are the essential lines:

    $NewServer = $ServerList.CreateElement("ServerInfo")

    $NewServer.SetAttribute("name",$ComputerName.ToString()) | Out-Null

    $NewServer.SetAttribute("xmlns","urn:serverpool-schema") | Out-Null

    $ServerList.ServerList.AppendChild($NewServer) | Out-Null

    So setting the right attribute in the right notation does the trick for us. Now I have the newly added server in Server Manager.

    Image of menu

    The same is true when it comes to adding the server to an existing group.

    $NewServerInGroup = $ServerList.CreateElement("ServerGroupMembership")

    $NewServerInGroup.SetAttribute("server",$ComputerName.ToString()) | Out-Null

    $NewServerInGroup.SetAttribute("serverGroupId",$PSItem.Id) | Out-Null

    $NewServerInGroup.SetAttribute("xmlns","urn:serverpool-schema") | Out-Null

    $ServerList.ServerList.AppendChild($NewServerInGroup) | Out-Null

    Because this is an existing group, we have to make sure that the group’s ID is added to the attributes of the entry. So this is how you add a new server to your list of managed servers. Simple, isn’t it? A new server group is shown here:

    Image of menu

    You may also want to add some custom groups. The added script, New-ServerManagerGroup.ps1, helps you take care of that. It creates a random number and uses it as the needed group ID.

    $Global:ServerGroupID = Get-Random -Maximum 1000

    $NewServerGroup = $ServerList.CreateElement("ServerGroupInfo")

    $NewServerGroup.SetAttribute("id",$Global:ServerGroupID) | Out-Null

    $NewServerGroup.SetAttribute("name",$Name) | Out-Null

    $NewServerGroup.SetAttribute("xmlns","urn:serverpool-schema") | Out-Null

    $ServerList.ServerList.AppendChild($NewServerGroup) | Out-Null

    I’ve added additional switches, such as –Backup (to save the previous ServerManager.xml) and –StartServerManager (for launching Server Manager after your additions). Be aware that the provided scripts always check for a servermanager.exe process and end this process silently for you.

    I hope these little scripts help the community, and I’m looking forward to your comments.

    The following scripts are uploaded on the Script Center Repository:

    ~Rolf

    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 Case-Specific Strings by Using PowerShell

    Summary: Use Windows PowerShell to find case-specific strings.

    Hey, Scripting Guy! Question How can I find a particular, case-sensitive word in a string?

    Hey, Scripting Guy! Answer Use Select-String and specify the –CaseSensitive switch:

    "Hey Scripting Guy","hey scripting guy" | Select-String -Pattern 'hey' -CaseSensitive

  • Weekend Scripter: Understanding PowerShell in Windows 7

    Summary: Microsoft Scripting Guy, Ed Wilson, talks about understanding Windows PowerShell in Windows 7.

    Microsoft Scripting Guy, Ed Wilson, is here. This morning I am sipping a cup of English Breakfast tea, with goji berries, lemon grass, and cinnamon. The taste is quite nice, and because the goji berries are sweet, I do not need to add any sugar or honey to my tea. Goji berries are not indigenous to Charlotte, North Carolina, so I use dried berries that I order with my other herbs and spices. Along with my tea, I am eating some homemade scones that the Scripting Wife made with the goji berries. They are rather lovely.

    One of the more common questions I get about Windows PowerShell 3.0 runs something like this,“I have Windows PowerShell 3.0, but I do not see the Get-Disk cmdlet.” (Or words to that effect.) Part of the confusion stems from confusing Windows PowerShell 3.0 with the operating system.

    Note   For information about installation, refer to Install PowerShell 3.0 on Windows 7.

    For example, in Windows 7, when I install Windows PowerShell 3.0, I have access to 355 cmdlets and functions. To find this information, I first imported all of the modules, and then I used the Get-Command cmdlet to retrieve all functions and cmdlets. This is shown here:

    Image of command output

    In Windows 8, I do not need to install Windows PowerShell 3.0 because it is part of the operating system. When I import all of the modules and count the number of cmdlets and functions in Windows 8, I come up with 988. The output is shown in the following image.

    Note  Interestingly enough, the output from $PSVersionTable is a little different in Windows 7 and Windows 8.

    Image of command output

    Look at the modules

    So, where does the difference between Windows PowerShell 3.0 in Windows 7 and In Windows 8 come from? Well, it comes from the modules. In Windows 8, many of the teams at Microsoft created modules to permit remote management of aspects of their configuration. In many cases, this took the form of wrapping various WMI classes that have been part of the operating system for a long time. Therefore, just because I am working in Windows 7, it does not mean that I am unable to use Windows PowerShell to manage it—but it will be a bit more difficult.

    So what are the modules that are available in Windows 7 after I install Windows PowerShell 3.0? They are listed here:

    PS C:\> Get-Module -list | select name

    Name

    ----

    AppLocker

    BitsTransfer

    CimCmdlets

    ISE

    Microsoft.PowerShell.Diagnostics

    Microsoft.PowerShell.Host

    Microsoft.PowerShell.Management

    Microsoft.PowerShell.Security

    Microsoft.PowerShell.Utility

    Microsoft.WSMan.Management

    PSDiagnostics

    PSScheduledJob

    PSWorkflow

    PSWorkflowUtility

    TroubleshootingPack

    To get an idea of the number of cmdlets in each module, I decide to create a custom property in the Select-Object cmdlet. Here is the command that I created (this is a single-line command that I broke into multiple lines for easier reading):

    Get-Module -list | select name,

    @{L='commands';E={(Get-command -commandtype Function, Cmdlet -module $_.name).count}} |

    sort commands -Descending| ft –auto

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

    Image of command output

    By examining the modules and the cmdlets, I can see where the Windows PowerShell 3.0 cmdlets and functions reside, and determine from whence they actually come.

    Join me tomorrow when I will examine Windows PowerShell 3.0 in Windows 8.

    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 Write BitLocker Recovery Key to Text File

    Summary: Use Windows PowerShell to write your BitLocker recovery key to a text file.

    Hey, Scripting Guy! Question If I forgot to save my BitLocker recovery key when I enabled BitLocker on my laptop, how can I use Windows PowerShell to write it to a text file so I can copy it to a USB key for safe keeping?

    Hey, Scripting Guy! Answer From an elevated Windows PowerShell console, use the Get-BitLockerVolume function, select -MountPoint C, choose the KeyProtector and the RecoveryPassword properties, and then redirect the output to a text file:

    (Get-BitLockerVolume -MountPoint C).KeyProtector.recoverypassword > c:\bitlockerkey.txt

  • Weekend Scripter: Understanding PowerShell in Windows 8

    Summary: Microsoft Scripting Guy, Ed Wilson, talks about understanding Windows PowerShell 3.0 in Windows 8.

    Microsoft Scripting Guy, Ed Wilson, is here. It is an exciting and great day! I have been working a bit to solidify the editorial calendar for the Hey, Scripting Guy! Blog. I can say that there are some absolutely awesome posts coming up in the next couple months. I am not just saying this because I am writing them. Nope. I have a great lineup of guest writers. The upcoming stuff will simply rock!

    Windows 8 posh stuff…

    One of the really great things about Windows 8 is the implementation of Windows PowerShell 3.0. But many of the really cool commands (cmdlets or functions) are not strictly Windows PowerShell 3.0. For example, one function I use on a regular basis when I am traveling is Get-NetAdapter. This command tells me if a network adapter is up. Because I toggle my wireless and my Ethernet adapter connections (on or off depending on the network), I often need to see if a particular adapter is up.

    Another function I use a lot when I am traveling is the Get-NetConnectionProfile function. This tells me how a particular network adapter has been identified by the operating system. I can modify the profile by using Set-NetConnectionProfile. I need to use this a lot when I am traveling and I want to demonstrate Windows PowerShell.

    Neither of the two previously mentioned functions are part of Windows PowerShell 3.0, per se. They are included in modules that ship with Windows 8. The associated modules are shown here:

    PS C:\> Get-Command Get-NetConnectionProfile, Get-NetAdapter

     

    CommandType     Name                                             ModuleName

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

    Function        Get-NetConnectionProfile                     NetConnection

    Function        Get-NetAdapter                                     NetAdapter

    Am I being pedantic? If so, it is not my intention. It is important to know where specific functionality arises, so that when I install Windows PowerShell 3.0 onto a computer running Windows 7, I will know what to expect. This concept will be important when Windows 8.1 ships with Windows PowerShell 4.0 because Windows PowerShell 4.0 in Windows 8.1 will expose certain cmdlets and functions that may not be available if I install Windows PowerShell 4.0 on a down-level system.

    Emulating capability

    With all the great commands in Windows 8, it is easy to forget that the capability comes from modules that ship with the operating system, and that they are not part of Windows PowerShell 3.0 core installation. But it is Windows PowerShell 3.0 that makes these cool modules shine. Most of the capability comes from the CIM infrastructure that is part of the Windows Management Framework 3.0 (where you obtain Windows PowerShell 3.0).

    For example, the Get-NetAdapter function uses CIM to expose network adapter information. It is very convenient. The command and its associated output are shown here:

    Image of command output

    I can achieve the same output in Windows 7 by using Windows PowerShell 3.0. I use the Get-CimInstance cmdlet, query the Win32_NetworkAdapter WMI class, and choose the appropriate properties. The command is a bit longer than just typing Get-NetAdapter, but if I use it all the time, all I need to do is write my own function. Following is the command (gcim is the alias for Get-CimInstance, Select is the alias for Select-Object, and ft is the alias for Format-Table). This command is a single-line command that I broke at the pipe character for readability.

    gcim win32_networkadapter |

    select netconnectionid, description, interfaceindex, macaddress, speed |

    ft * -auto

    Here is the command and the output from the command:

    Image of command output

    Join me tomorrow as I begin a series of posts called Windows PowerShell Workflow for Mere Mortals. It is a great 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