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

PowerShell Spotlight: Three Upcoming Spotlight Events

$
0
0

Summary: Windows PowerShell MVP, Teresa Wilson, spotlights three Windows PowerShell events.

Hey, Scripting Guy! Question Microsoft Scripting Guy, Ed Wilson, is here. I was talking with Teresa (The Scripting Wife) about some ideas she had for sharing information with IT professionals. We came up with the idea for her to write a blog post once a month called PowerShell Spotlight. You can look for it the last Saturday of each month right here until she runs out of useful things to share. Without further ado, here is Microsoft MVP and Honorary Scripting Guy, Teresa Wilson.

Hey, Scripting Guy! Answer Hello everyone,

As Ed mentioned, we were talking about the availability of information and how hard it is to have one go-to place for all things Windows PowerShell. I volunteered to write a post once a month and “spotlight” something different each month. If you have any requests or suggestions, please feel free to write a comment on this post.

Today I want to spotlight three events that are coming up in the next few months. Here are the dates and locations:

There is also going to be the Jacksonville IT Pro Camp on June 13, 2015 in Jacksonville FL that Ed and I will be attending. They are currently having their call for speakers. Here is the registration page.

Also don’t forget the local and virtual User Group meetings.

To find a User Group in a city near you, check Powershell.org for a list of User Groups. If you are the leader of a User Group, and you have not sent information to PowerShell.org to list your group, it is not too late. Send us an email.

If there is not a User Group near you, you have options. You can join the Virtual User Group. Also, some of the groups broadcast their meetings. Give me a shout if you are having trouble finding information. I am happy to help.

Have a great day. See you next month with a new PowerShell Spotlight.

~Teresa

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 Network Adapter Power Settings

$
0
0

Summary: Use Windows PowerShell to display network adapter power settings.

Hey, Scripting Guy! Question How can I use Windows PowerShell to see if my laptop is going to sleep—it keeps dropping off of the
            wireless network.

Hey, Scripting Guy! Answer Use the Get-NetAdapterPowerManagement Windows PowerShell command to display the power
           management settings for your network adapter.

Weekend Scripter: Use PowerShell to Troubleshoot Group Policy Part 2

$
0
0

Summary: Guest blogger, Alex Verboon, continues his series about using Windows PowerShell to troubleshoot Group Policy.

Microsoft Scripting Guy, Ed Wilson, is here. Welcome back guest blogger, Alex Verboon. Today Alex adds to his previous blog about using Windows PowerShell to troubleshoot Group Policy. He provides a script that automates this process. You can read his blog at Anything about IT.

Take it away Alex…

In my previous post, Use PowerShell to Troubleshoot Group Policy, I shared a script that retrieves the Group Policy processing time. As shown here, when specifying the optional –ShowDetails switch, the Get-GPProcessingTime script output also displays the Correlation:ActivityID that represents one instance of Group Policy processing.

To get all the details of what happened during that Group Policy processing cycle, we simply retrieve all events that have the corresponding ActivityID:

Get-GPEventByCorrelationID -Computer TestClient1 -CorrelationID f7cb68e1-f6da-4d23-8fca-c4cb85158de2

Here is the script output:

Image of command output

Following is the full script. You can download this script from the Script Center Repository at Get-GPEventByCo​rrelationID.

function Get-GPEventByCorrelationID

{

<#

.Synopsis

   Get Group Policy Eventlog entries by Correlation ID

.DESCRIPTION

   This function retrieves Group Policy event log entries filtered by Correlation ID from the specified computer

.EXAMPLE

   Get-GPEventByCorrelationID -Computer TestClient -CorrelationID A2A621EC-44B4-4C56-9BA3-169B88032EFD

 

TimeCreated                     Id LevelDisplayName Message                                                         

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

7/28/2014 5:31:31 PM          5315 Information      Next policy processing for CORP\CHR59104$ will be attempted in...

7/28/2014 5:31:31 PM          8002 Information      Completed policy processing due to network state change for co...

7/28/2014 5:31:31 PM          5016 Information      Completed Audit Policy Configuration Extension Processing in 0...

.......

 

#>

    [CmdletBinding()]

    Param

    (

        [Parameter(Mandatory=$true,

        ValueFromPipelineByPropertyName=$true,

        HelpMessage="Enter Computername(s)",

        Position=0)]

        [String]$Computer = "localhost",

        # CorrelationID

        [Parameter(Mandatory=$true,

        ValueFromPipelineByPropertyName=$true,

        HelpMessage="Enter CorrelationID",

        Position=0)]

        [string]$CorrelationID

        )

 

    Begin

    {

        $Query = '<QueryList><Query Id="0" Path="Application"><Select Path="Microsoft-Windows-GroupPolicy/Operational">*[System/Correlation/@ActivityID="{CorrelationID}"]</Select></Query></QueryList>'

        $FilterXML = $Query.Replace("CorrelationID",$CorrelationID)

    }

    Process

    {

        $orgCulture = Get-Culture

        [System.Threading.Thread]::CurrentThread.CurrentCulture = New-Object "System.Globalization.CultureInfo" "en-US"

        $gpevents = Get-WinEvent -FilterXml $FilterXML -ComputerName $Computer

        [System.Threading.Thread]::CurrentThread.CurrentCulture = $orgCulture

    }

    End

    {

        [System.Threading.Thread]::CurrentThread.CurrentCulture = New-Object "System.Globalization.CultureInfo" "en-US"

        $gpevents | Format-Table -Wrap -AutoSize -Property TimeCreated, Id, LevelDisplayName, Message

        [System.Threading.Thread]::CurrentThread.CurrentCulture = $orgCulture

     }

}

In addition to what I have posted here and in the Script Center Repository, I found the following script written by Thomas Bouchereau (PFE), which is similar: Group Policy processing events collection with PowerShell.

~Alex

Thank you, Alex, for sharing your time and knowledge. This is an awesome script and I wanted to make sure we shared it with the community. Join me tomorrow when Windows PowerShell MVP, Richard Siddaway, begins a great series about working with the registry. 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

PowerTip: Back up GPOs with PowerShell

$
0
0

Summary: Use Windows PowerShell to back up all GPOs in a domain.

Hey, Scripting Guy! Question How can I use Windows PowerShell to generate a backup of all Group Policy Objects in a domain?

Hey, Scripting Guy! Answer Use the Backup-GPO cmdlet from the Remote Server Administration Tools (RSAT).
           Specify a name, path, domain, and server, for example:

Backup-GPO -All -Path \\share\backups -Comment "weekly Backup" -Domain nwtraders.com -Server dc1

Registry Cmdlets: Working with the Registry

$
0
0

Summary: Richard Siddaway investigates how to use CIM to manage the registry.

Honorary Scripting Guy, Richard Siddaway, here filling in for my good friend The Scripting Guy. Today, I'm starting a series about registry cmdlets by investigating how to work with the registry.

The bad news is that there aren’t any cmdlets for working with the registry. There’s a Registry provider, which means you can use the Item and ItemProperty cmdlets to manage the local registry—but there aren’t any specific registry cmdlets associated with the provider.

The good news is that we can adopt the approach that many teams at Microsoft have taken and create our own by using cmdlet definition XML (CDXML). A Common Information Model (CIM) class is wrapped in some fairly simple XML and published as a Windows PowerShell module. If you look in the Modules folder on a computer running Windows 8.1, Windows 8, Windows Server 2012 R2, or Windows Server 2012, you will find many files with a CDXML extension:

Get-ChildItem -Path C:\Windows\System32\WindowsPowerShell\v1.0\Modules -Filter *.CDXML -Recurse

These files are a great resource for figuring out how CDXML should be constructed. Other useful resources include:

By the end of this series, you will have a Registry module that will make working with the registry much easier, and you will have learned how to use CDXML so that you can create other modules based on your favorite CIM classes.

First though, we should have a quick recap of using CIM to work with the registry.

Note Although there is a technical difference between CIM and WMI, I will be using them interchangeably, which seems to be common practice.

The registry is accessed through the StdRegProv class. You can examine the class like this:

Get-CimClass -Namespace root\cimv2 -ClassName StdRegProv

  NameSpace: ROOT/cimv2

CimClassName            CimClassMethods   CimClassProperties

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

StdRegProv             {CreateKey, Delet... {}

The class is also available in the root\default namespace. This is the only option if you are running Windows XP or Windows Server 2003. These versions are no longer supported, so we’ll use the root\cimv2 namespace for the remainder of the series. If you want to check if the classes are the same, you can examine the root\default version like this:

Get-CimClass -Namespace root\default -ClassName StdRegProv

When you look at the StdRegProv class, the first thing you notice is that it has no properties. The class provides methods only. To drill into the methods:

$class = Get-CimClass -Namespace root\cimv2 -ClassName StdRegProv

$class.CimClassMethods | select Name

Name

----

CreateKey

DeleteKey

EnumKey

EnumValues

DeleteValue

SetDWORDValue

SetQWORDValue

GetDWORDValue

GetQWORDValue

SetStringValue

GetStringValue

SetMultiStringValue

GetMultiStringValue

SetExpandedStringValue

GetExpandedStringValue

SetBinaryValue

GetBinaryValue

CheckAccess

SetSecurityDescriptor

GetSecurityDescriptor

As shown here, all the methods are static:

£> $class.CimClassMethods["GetSTRINGvalue"] | Format-List

Name    : GetStringValue

ReturnType : UInt32

Parameters : {hDefKey, sSubKeyName, sValueName, sValue}

Qualifiers : {implemented, static}

This means that you don’t need an instance of the class to work with—you can simply use the methods. The parameters for these methods are relatively straightforward:

£> $class.CimClassMethods["GetSTRINGvalue"].Parameters

Name               CimType Qualifiers

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

hDefKey                  UInt32 {ID, IN}

sSubKeyName        String {ID, IN}

sValueName            String {ID, in}

sValue                      String {ID, out}

This is where we meet the first nasty bit. The hdefkey parameter defines the registry hive you want to work with. It’s an unsigned integer that can take the following values:

HKEY_CLASSES_ROOT = 2147483648 (0x80000000)

HKEY_CURRENT_USER = 2147483649 (0x80000001)

HKEY_LOCAL_MACHINE = 2147483650 (0x80000002)

HKEY_USERS = 2147483651 (0x80000003)

HKEY_CURRENT_CONFIG = 2147483653 (0x80000005)

HKEY_DYN_DATA = 2147483654 (0x80000006)

This list shows the hive and the related unsigned integer as a decimal and hexadecimal number. I have found that it’s easiest to define these values as variables. For instance, to work with the HKEY_LOCAL_MACHINE hive, use:

[uint32]$hklm = 2147483650

Let’s look at a little Windows PowerShell history for a moment...

When Windows PowerShell 1.0 launched, it immediately gave us a way to work with WMI (Get-WmiObject). That was a huge step forward from using VBScript. Unfortunately, we couldn’t use the StdRegProv class directly because of its static methods. The answer was to use the [wmiclass] type accelerator:

$reg = [wmiclass]"\\.\root\cimv2:StdRegprov"

Then you can use Get-Member like this:

$reg | Get-Member

Now you'll see an object from the System.Management.ManagementClass:

System.Management.ManagementClass#ROOT\cimv2\StdRegProv

I tend to use variables for things like registry keys and values because it makes my code reusable. A couple of relatively safe values to use are:

$subkey = "SOFTWARE\Microsoft\Internet Explorer"

$value = "Version"

You can then call a method on the class:

$reg.GetSTRINGvalue($hklm, $subkey, $value)

The important parts of the results are:

ReturnValue   : 0

sValue      : 9.11.9600.17126

ReturnValue is the return code. A value of 0 in the ReturnValue is good. Anything else is bad, and could be very bad. Finding what the return code means can be difficult, but some information is available if you search WMI return values.

The sValue property holds the return value you want. You can access it directly by using standard techniques:

$reg.GetSTRINGvalue($hklm, $subkey, $value) | select -ExpandProperty sValue

     –or–

($reg.GetSTRINGvalue($hklm, $subkey, $value)).sValue

This technique is still valid and works with the latest versions of Windows PowerShell. However, working with the registry became much easier in Windows PowerShell 2.0 when Invoke-WmiMethod joined the game. Our registry access code became:

Invoke-WmiMethod -Namespace root\cimv2 -Class StdRegProv -Name GetSTRINGvalue -ArgumentList $hklm, $subkey, $value

However, life is never straightforward...a bit of a problem dropped into our laps. To explain, I need to create a registry key to work with. I can use the $reg object that I created earlier:

$newkey = "SOFTWARE\HSGtest"

$reg.CreateKey($hklm, $newkey)

And let’s add a value:

$newname = 'Date'

$newvalue = 'June 2013'

$reg.SetSTRINGvalue($hklm, $newkey, $newname, $newvalue)

And finally, let's test that it’s created correctly:

$reg.GetSTRINGvalue($hklm, $newkey, $newname)

The truncated output shows:

ReturnValue      : 0

sValue           : June 2013

Oops! This where I realize that I’ve used the wrong data, so now I need to modify the data:

$newvalue = 'June 2014'

And for a change, I’ll use Invoke-WmiMethod:

Invoke-WmiMethod -Namespace root\cimv2 -Class StdRegProv -Name SetSTRINGvalue $hklm, $newkey, $newname, $newvalue

A return code of 0 indicates that it worked. But let’s assume I’m a bit paranoid and I want to check the data:

$reg.GetSTRINGvalue($hklm, $newkey, $newname)

What I get is:

ReturnValue   : 0

sValue      : June 2013

In reality, the value hasn’t been changed. This isn’t a Windows PowerShell issue. It's related to the underlying .NET classes. It turns out that when you are using Invoke-WmiMethod, the order of the arguments matters. The cmdlet expects them in alphabetical order, not the order the documentation shows (which is the order that you’d use if using the [wmiclass] approach).

This problem will be most noticeable if the arguments are different data types. You get a nice big juicy error message that states you have a type mismatch: code 2147749893. The quick way to check the correct order of arguments is to use Get-CimClass:

$class = Get-CimClass -Namespace root\cimv2 -ClassName StdRegProv

$class.CimClassMethods["SetSTRINGvalue"].Parameters

Examining the Name of the parameters shows this:

Name

----

hDefKey

sSubKeyName

sValue

sValueName

Let’s retry it in that order:

Invoke-WmiMethod -Namespace root\cimv2 -Class StdRegProv -Name SetSTRINGvalue $hklm, $newkey, $newvalue, $newname

$reg.GetSTRINGvalue($hklm, $newkey, $newname)

And it works.

One way to avoid this confusion is to use the CIM cmdlets, which were introduced in Windows PowerShell 3.0. The problem goes away because you have to give argument name and value pairs:

To set data:

$newvalue = ‘June 2015’

Invoke-CimMethod -Namespace root\cimv2 -ClassName StdRegProv -MethodName SetSTRINGvalue -Arguments @{hDefKey=$hklm; sSubKeyName=$newkey; sValueName=$newname; sValue=$newvalue}

And to read data:

Invoke-CimMethod -Namespace root\cimv2 -ClassName StdRegProv -MethodName GetSTRINGvalue -Arguments @{hDefKey=$hklm; sSubKeyName=$newkey; sValueName=$newname}

This still leaves us with a lot of typing. Wouldn’t it be better if we could do this:

Set-RegistrySTRING -Hive HKLM -SubKey $newkey -ValueName $newname -Value 'April 2015'

Get-RegistrySTRING -Hive HKLM -SubKey $newkey -ValueName $newname

These are cmdlets from the module that I’m going to show you how to create in the next few posts, but for now I need to clean up my registry:

Remove-RegistryKey -Hive HKLM -SubKey $newkey

Bye for now. Next time, we’ll start digging into how we can use CDXML to create registry cmdlets.

Biography

Richard Siddaway is based out of the UK. He spends his time automating anything and everything, for Kelway, Ltd. A 7-year Windows PowerShell MVP, Richard is a prolific blogger, mainly about Windows PowerShell (see Richard Siddaway's Blog). Richard has been a director at PowerShell.org since the inception of that organization, and he is a frequent speaker at Windows PowerShell user groups and conferences. He has written a number of books: PowerShell in Practice, PowerShell and WMI, PowerShell in Depth (co-author), PowerShell Dive (co-editor), and Learn Active Directory Management in a Month of Lunches, which features lots of Windows PowerShell. All of the books are available from Manning Publications.

We invite you to follow The Scripting Guys on Twitter and Facebook. If you have any questions, send an email to The Scripting Guys at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. Until then, remember eat your cmdlets every day with a dash of creativity.

Richard Siddaway, Windows PowerShell MVP and Honorary Scripting Guy

PowerTip: Use PoweShell to Search for CIM Classes

$
0
0

Summary: Learn how to use Windows PowerShell to search for CIM classes.

Hey, Scripting Guy! Question How can I use Windows PowerShell to find a CIM class on my machine?

Hey, Scripting Guy! Answer Use Get-WmiObject in List mode. For instance, to find the class for working with the registry, use:

Get-WmiObject -Namespace root -Class StdRegProv -List –Recurse

     Note If you don’t know where a class can be found, always start at the root.

If you want to find the classes for working with disks:

Get-WmiObject -Namespace root -Class *disk* -List -Recurse

If you know the namespace, you can simplify the search:

Get-WmiObject -Namespace root\cimv2 -Class *disk* -List –Recurse

     Note If you don’t provide a namespace, the default of root\cimv2 is used.

When you find likely classes, use Get-CimClass to investigate details.

Registry Cmdlets: First Steps with CDXML

$
0
0

Summary: Richard Siddaway shows how to start creating CDXML cmdlets.

Honorary Scripting Guy, Richard Siddaway, here today filling in for my good friend, The Scripting Guy. This is the second post in a series. Yesterday, in Registry Cmdlets: Working with the Registry, I explained that there aren’t any cmdlets for working directly with the registry. I showed some examples of using cmdlets that I’ve created to access the registry. The cmdlets are created from the WMI registry class, StdRegProv, by using CDXML.

In this post, I’ll show you how to get started with CDXML. Before that, though, I’d better explain CDXML...

Cmdlet definition XML (CDXML) is a way to create a Windows PowerShell module from a WMI class by using the cmdlets-over-objects technology that was introduced in Windows PowerShell 3.0. As usual, it’s always easier to show you an example:

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

<PowerShellMetadata xmlns="http://schemas.microsoft.com/cmdlets-over-objects/2009/11">

 <Class ClassName="ROOT\cimv2\Win32_BIOS">

  <Version>1.0</Version>

  <DefaultNoun>Bios</DefaultNoun>

 

  <InstanceCmdlets>

   <GetCmdletParameters DefaultCmdletParameterSet="DefaultSet" >

      

   </GetCmdletParameters>

  </InstanceCmdlets>

 </Class>

 </PowerShellMetadata>

The first two lines in the previous command are header information, and they have to be present in all CDXML files. You also need to state the WMI class you want to use:

<Class ClassName="ROOT\cimv2\Win32_BIOS">

The namespace and class have to be supplied. This is equivalent to:

Get-CimInstance -Namespace root/CIMV2 -ClassName Win32_BIOS

You can only use a single WMI class in a CDXML module. If you need to access several WMI classes in your module, create a CDXML file per class, and use a module manifest to perform the load.

The version is arbitrary, and is up to you as to how it is changed as you change the module. Here is an example:

<Version>1.0</Version>

Windows PowerShell cmdlets have a noun-verb naming convention. CDXML allows you to set a default noun:

<DefaultNoun>Bios</DefaultNoun>

If you don’t supply a noun for the name of any cmdlet in your module, it will use the default noun.

The following four lines define the standard Get cmdlet in the module:

<InstanceCmdlets>

   <GetCmdletParameters DefaultCmdletParameterSet="DefaultSet" >

   </GetCmdletParameters>

</InstanceCmdlets>

The remaining XML closes the tags.

Save the XML with a .cdxml extension. I’ve used Bios.cdxml. You treat the CDXML file as a Windows PowerShell module. It’s most closely analogous to a .psm1 file. Create a folder on your module path with the same name as your module and save the file in that folder. The module will be automatically loaded in the same way as any other Windows PowerShell module when you start a Windows PowerShell session.

If you are working on the module in a series of stages, save it in a working folder that’s not on your module path. You can then load the module directly:

Import-Module .\bios.cdxml

If you are testing and debugging, you may need to load the module back into your Windows PowerShell session. You can ensure that you get the latest version of the module by using the –Force parameter:

Import-Module .\bios.cdxml –Force

£> Get-Module -Name Bios | Format-Table -AutoSize

ModuleType Version Name ExportedCommands

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

Cim    1.0   bios Get-Bios

The module contains a single cmdlet: Get-Bios. The module type shows as CIM. If you use a module manifest, the module type will change to Manifest.

If you use Get-Command on the cmdlet, for example:

£> Get-Command Get-Bios -Syntax

Get-Bios [-CimSession <CimSession[]>] [-ThrottleLimit <int>] [-AsJob] [<CommonParameters>]

...you’ll see that there are some parameters that you didn’t define: –CimSession, –ThrottleLimit, and –AsJob. These are always generated on a CDXML module. You get this functionality for free. You also get the standard common parameters without any effort on your part.

You use the cmdlet in the same manner as any other cmdlet:

£> Get-Bios

SMBIOSBIOSVersion : 2.04.0950

Manufacturer   : American Megatrends Inc.

Name       : 2.04.0950

SerialNumber   : 036685734653

Version      : OEMA - 1072009

This is the same data and format that you’d get by using the WMI class directly:

£> Get-CimInstance -ClassName Win32_BIOS

SMBIOSBIOSVersion : 2.04.0950

Manufacturer   : American Megatrends Inc.

Name       : 2.04.0950

SerialNumber   : 036685734653

Version      : OEMA - 1072009

You can use Get-Help on the cmdlet. It will only show the basic syntax. If you want extensive help, you need to create an XML-based external Help file for the module. There is no way to provide inline, comment-based Help like you can for a Windows PowerShell module.

Now that you’ve seen a basic CDXML module, let’s start putting together our Registry module. This code is the first step:

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

<PowerShellMetadata xmlns="http://schemas.microsoft.com/cmdlets-over-objects/2009/11">

 <Class ClassName="root\cimv2\StdRegProv">

  <Version>1.0.0.0</Version>

  <DefaultNoun>Registry</DefaultNoun>

 

  <StaticCmdlets>

   <Cmdlet>

    <CmdletMetadata Verb="Get" Noun="RegistrySTRING" ConfirmImpact="Low"/>

    <Method MethodName="GetSTRINGvalue">

     <ReturnValue>

      <Type PSType="System.UInt32"/>

      <CmdletOutputMetadata>

      </CmdletOutputMetadata>

     </ReturnValue>

    

     <Parameters>

      <Parameter ParameterName="hDefKey" >

       <Type PSType="System.UInt32" />

       <CmdletParameterMetadata PSName="Hive">

       </CmdletParameterMetadata>

      </Parameter>

      <Parameter ParameterName="sSubKeyName" >

       <Type PSType="System.String" />

       <CmdletParameterMetadata PSName="SubKey">

       </CmdletParameterMetadata>

      </Parameter>

      <Parameter ParameterName="sValueName" >

       <Type PSType="System.String" />

       <CmdletParameterMetadata PSName="ValueName">

       </CmdletParameterMetadata>

      </Parameter>

      <Parameter ParameterName="sValue">

       <Type PSType="System.String" />

       <CmdletOutputMetadata />

      </Parameter>

     </Parameters>

    </Method>

   </Cmdlet>  

  </StaticCmdlets>

  </Class>

</PowerShellMetadata>

The first few lines define the class and version, as you’ve seen previously. I used Registry as the default noun. The next line is very important. In our Registry module, it is:

<StaticCmdlets>

The corresponding line in the BIOS example was:

<InstanceCmdlets>

The difference is that with the BIOS example, you are working with an instance of the object that exists. When you start your computer, the BIOS loads, and that information is available to you. You can’t create another instance of the BIOS!

Other classes where you are dealing with instances include Win32_LogicalDisk, Win32_ComputerSystem, and Win32_OperatingSystem. These are all objects that exist on your system, and therefore, they can have instances.

The Registry class is a little different. As you saw yesterday, the StdRegProv class provides a set of static methods for working with the registry. You don’t have instances in this case. The <StaticCmdlets> element tells the system that you are dealing with static members of the class rather than instances of CIM objects.

Eventually, the module will create a cmdlet for most methods in the StdRegProv class. To get a quick reminder of the methods available, you can use:

Get-CimClass -ClassName StdRegProv | select -ExpandProperty CimClassMethods

Many registry properties are strings, so I’m going to start with the GetStringValue method:

    <CmdletMetadata Verb="Get" Noun="RegistrySTRING" ConfirmImpact="Low"/>

    <Method MethodName="GetSTRINGvalue">

The cmdlet metadata sets the verb as Get and the noun as RegistrySTRING (this is capitalized for demonstration purposes, but feel free to revert to normal Windows PowerShell case conventions if you desire). This cmdlet will be called Get-RegistrySTRING and it will use the GetSTRINGvalue method.

The methods in CIM classes return data and a return value. If the return value is zero (0), it worked correctly. Any other value indicates failure. A return value is useful when troubleshooting registry issues, so you should include it in your cmdlet:

     <ReturnValue>

      <Type PSType="System.UInt32"/>

      <CmdletOutputMetadata>

      </CmdletOutputMetadata>

     </ReturnValue>

The type is very important. It must be System.UInt32, that is, an unsigned 32-bit integer. CIM works with unsigned integers, which only have positive values:

£> [uint32]::MinValue

0

£> [uint32]::MaxValue

4294967295

In contrast, the standard integer can take positive and negative values:

£> [int32]::MinValue

-2147483648

£> [int32]::MaxValue

2147483647

The last step in defining the cmdlet is to supply the information that is required to define its parameters. Each parameter is defined in a separate parameter block. The GetStringValue method has four arguments—three input arguments and one output argument.

Get-CimClass and the WMI documentation refer to method parameters rather than arguments. To avoid additional confusion, I'm using arguments when I am talking about the method and I'm using parameters when I am talking about the resultant cmdlet.

The first input argument, hDefKey, defines the hive to be accessed. Remember that this is a number, for instance:

HKEY_LOCAL_MACHINE = 2147483650 (0x80000002)

It is supplied as an unsigned integer and the method argument name is overridden, so the cmdlet parameter name is Hive rather than hDefKey. This isn’t necessary, but it makes the cmdlet easier to use. The name of your cmdlet parameter is your choice—use whatever makes the cmdlet easier to use for you.

      <Parameter ParameterName="hDefKey" >

       <Type PSType="System.UInt32" />

       <CmdletParameterMetadata PSName="Hive">

       </CmdletParameterMetadata>

      </Parameter>

The sSubKeyName and sValueName arguments for GetStringValue define the value you are reading from the registry. Both use "System.String" as their type, and I’ve overridden the argument names so the cmdlet’s parameters are SubKey and ValueName respectively:

      <Parameter ParameterName="sSubKeyName" >

       <Type PSType="System.String" />

       <CmdletParameterMetadata PSName="SubKey">

       </CmdletParameterMetadata>

      </Parameter>

 

      <Parameter ParameterName="sValueName" >

       <Type PSType="System.String" />

       <CmdletParameterMetadata PSName="ValueName">

       </CmdletParameterMetadata>

      </Parameter>

The final argument for the GetStringValue method is sValue. This again is a string, but it is the property for the return object that holds the value read from the registry. <CmdletOutputMetadata /> is required to ensure the data is output:

      <Parameter ParameterName="sValue">

       <Type PSType="System.String" />

       <CmdletOutputMetadata />

      </Parameter>

   Note Renaming output parameters doesn’t seem to be possible.

Save the file with the CDXML definition as registry1.cdxml. You can load it into Windows PowerShell:

£> Get-Command -Module registry1

CommandType   Name                        ModuleName

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

Function    Get-RegistrySTRING                 registry1

£> Get-Command Get-RegistrySTRING -Syntax

Get-RegistrySTRING [-Hive <uint32>] [-SubKey <string>] [-ValueName <string>] [-CimSession <CimSession[]>] [-ThrottleLimit <int>] [-AsJob] [-WhatIf] [-Confirm] [<CommonParameters>]

You can use the following commands to use it.

To define the hive to use (in this case, HKLM):

 [uint32]$hklm = 2147483650

To define the subkey and value to read:

 $subkey = "SOFTWARE\Microsoft\Internet Explorer"

 $value = "Version"

To use the cmdlet:

Get-RegistrySTRING -Hive $hklm -SubKey $subkey -ValueName $value

This gives the following result:

sValue              ReturnValue

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

9.11.9600.17498      0

Now you know how to get started creating cmdlets for working with the registry. This series will continue tomorrow when I will show you how to change the code to enable you to use friendly names for the registry hives, make parameters mandatory, and perform validation on the values input to parameters.

We invite you to follow The Scripting Guys on Twitter and Facebook. If you have any questions, send an email to The Scripting Guys at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. Until then, remember eat your cmdlets every day with a dash of creativity.

Richard Siddaway, Windows PowerShell MVP and Honorary Scripting Guy

PowerTip: Use PowerShell to Find Parameters for CIM Class Method

$
0
0

Summary: Learn how to discover the parameters for a method in a CIM class.

Hey, Scripting Guy! Question How can I find the parameters of a CIM class method, such as GetStringValue in the StdRegprov class?

Hey, Scripting Guy! Answer Use Get-CimClass to get the class:

$class = Get-CimClass -ClassName StdRegProv

To view the methods:

$class.CimClassMethods

To view the parameters of a particular method:

$class.CimClassMethods["GetStringValue"].Parameters

You will see the parameter name and data type. The qualifiers will tell you if it’s an input or output parameter.


Registry Cmdlets: Advanced CDXML

$
0
0

Summary: Richard Siddaway shows some advanced features in CDXML.

Honorary Scripting Guy, Richard Siddaway, here today filling in for my good friend, The Scripting Guy. This is the third post in a series. To catch up, read:

Yesterday, you saw that you can create a Windows PowerShell cmdlet from the StdRegProv CIM class by using CDXML, which enables you to read a string value from the registry. Today, I want to show you some of the advanced features of CDXML. These enable you to make your CDXML cmdlet act like any other Windows PowerShell cmdlet. For instance, you can make parameters mandatory and validate the values that are input to parameters.

Before that though, I want to show something that makes working with the registry so much easier. One of the biggest pain points when working with the CIM Registry provider, StdRegProv, is those awful numbers you have to remember—the numbers that define the hives:

HKEY_CLASSES_ROOT = 2147483648 (0x80000000)

HKEY_CURRENT_USER = 2147483649 (0x80000001)

HKEY_LOCAL_MACHINE = 2147483650 (0x80000002)

HKEY_USERS = 2147483651 (0x80000003)

HKEY_CURRENT_CONFIG = 2147483653 (0x80000005)

HKEY_DYN_DATA = 2147483654 (0x80000006)

They are required when using the cmdlet we created yesterday:

[uint32]$hklm = 2147483650

$subkey = "SOFTWARE\Microsoft\Internet Explorer"

$value = "Version"

Get-RegistrySTRING -Hive $hklm -SubKey $subkey -ValueName $value

But wouldn’t it be great if you could provide a friendly value for the hive—something like this:

Get-RegistrySTRING -Hive HKLM -SubKey $subkey -ValueName $value

There is a simple way to achieve this. The first step is to change the end of your CDXML file from this:

  </Class>

</PowerShellMetadata>

...to this:

  </Class>

  <Enums>

    <Enum EnumName="RSPSNA.Registry.Hive" UnderlyingType="System.UInt32">

      <Value Name="HKCR" Value="2147483648" />

      <Value Name="HKCU" Value="2147483649" />

      <Value Name="HKLM" Value="2147483650" />

      <Value Name="HKUS" Value="2147483651" />

      <Value Name="HKLocalMachine" Value="2147483650" />

      <Value Name="HKCC" Value="2147483653" />

    </Enum>

  </Enums>

</PowerShellMetadata>

You are adding an enumeration definition to the CDXML file. It has a name (in this case, EnumName="RSPSNA.Registry.Hive") and an underlying type (- UnderlyingType="System.UInt32"). You then need to define the values in the enumeration:

<Value Name="HKCR" Value="2147483648" />

Each value has a name-value pair as shown. It is possible to define multiple names for the same value:

      <Value Name="HKLM" Value="2147483650" />

      <Value Name="HKLocalMachine" Value="2147483650" />

This means that you can provide your users with a number of different ways of defining the hive key, and they can use whichever fits their style. I prefer the 4-letter acronyms—it’s less typing!

You also have to change the parameter definitions. Yesterday, you saw this command to define the hive parameter:

            <Parameter ParameterName="hDefKey" >

              <Type PSType="System.UInt32" />

              <CmdletParameterMetadata PSName="Hive">

              </CmdletParameterMetadata>

            </Parameter>

You need to change it to use the enumeration:

            <Parameter ParameterName="hDefKey" >

              <Type PSType="RSPSNA.Registry.Hive" />

              <CmdletParameterMetadata PSName="Hive">

              </CmdletParameterMetadata>

            </Parameter>

The only change is on the Type line where the type is changed to match the name of the enumeration. The name of the type, and therefore the enumeration, is arbitrary and under your control. I recommend that you create a naming scheme for enumerations in your organization.

In my testing, I named this version of the module registry2.cdxml. You import the module and set the values for the subkey and value you want to read:

Import-Module .\registry2.cdxml -Force

$subkey = "SOFTWARE\Microsoft\Internet Explorer"

$value = "Version"

And then use the cmdlet like this:

Get-RegistrySTRING -Hive HKLM -SubKey $subkey -ValueName $value

The act of defining an enumeration automatically forces validation of the input:

Get-RegistrySTRING -Hive HKLL -SubKey $subkey -ValueName $value

Get-RegistrySTRING : Cannot process argument transformation on parameter 'Hive'. Cannot convert value "HKLL" to type

"Microsoft.PowerShell.Cmdletization.GeneratedTypes.RSPSNA.Registry.Hive". Error: "Unable to match the identifier name

HKLL to a valid enumerator name.  Specify one of the following enumerator names and try again: HKCR, HKCU, HKLM,HKLocalMachine, HKUS, HKCC"

At line:1 char:26

+ Get-RegistrySTRING -Hive HKLL -SubKey $subkey -ValueName $value

+                          ~~~~

    + CategoryInfo          : InvalidData: (:) [Get-RegistrySTRING], ParameterBindingArgumentTransformationException

    + FullyQualifiedErrorId : ParameterArgumentTransformationError,Get-RegistrySTRING

As with other Windows PowerShell cmdlets, you even get a helpful hint as to the accepted values. As a side note, Tab completion works on the enumeration, so type:

Get-RegistrySTRING –Hive

...and then use the Tab key to cycle through the allowed values.

The hive defaults to HKLM, so you can do this:

Get-RegistrySTRING -SubKey $subkey -ValueName $value

This is not a practice I recommend, though. If you explicitly state the registry hive you want to access, it makes troubleshooting easier.

You can add other validation to the cmdlet parameters in a similar manner to advanced functions. The simplest change is to make a parameter mandatory. Add the IsMandatory="true" element to the CmdletParameterMetadata node, and you now have a mandatory parameter:

            <Parameter ParameterName="hDefKey" >

              <Type PSType="RSPSNA.Registry.Hive" />

              <CmdletParameterMetadata IsMandatory="true" PSName="Hive">

              </CmdletParameterMetadata>

            </Parameter>

Like with an existing cmdlet or an advanced function, if you don’t specify the value of a mandatory parameter you will be prompted.

This works as you would expect:

Import-Module .\registry3.cdxml -Force

Get-RegistrySTRING -Hive HKLM -SubKey "SOFTWARE\Microsoft\Internet Explorer" -ValueName Version

Registry3.cdxml is the version where I added the mandatory parameter. If you don’t specify the –Hive parameter, you will be prompted:

£> Get-RegistrySTRING -SubKey "SOFTWARE\Microsoft\Internet Explorer" -ValueName Version

cmdlet Get-RegistrySTRING at command pipeline position 1

Now, supply values for the parameters—you won’t be allowed to specify the parameter without a value:

£> Get-RegistrySTRING -Hive  -SubKey "SOFTWARE\Microsoft\Internet Explorer" -ValueName Version

Get-RegistrySTRING : Missing an argument for parameter 'Hive'. Specify a parameter of type

'Microsoft.PowerShell.Cmdletization.GeneratedTypes.RSPSNA.Registry.Hive' and try again.

At line:1 char:20

+ Get-RegistrySTRING -Hive  -SubKey "SOFTWARE\Microsoft\Internet Explorer" -ValueN ...

+                    ~~~~~

    + CategoryInfo          : InvalidArgument: (:) [Get-RegistrySTRING], ParameterBindingException

    + FullyQualifiedErrorId : MissingArgument,Get-RegistrySTRING

There are a set of tags for setting validation on parameter input; for instance, to validate that the input isn’t null or empty:

            <Parameter ParameterName="sValueName" >

              <Type PSType="System.String" />

              <CmdletParameterMetadata PSName="ValueName">

                <ValidateNotNullOrEmpty />

              </CmdletParameterMetadata>

            </Parameter>

After importing the changed module, you can use it as before:

Get-RegistrySTRING -Hive HKLM -SubKey "SOFTWARE\Microsoft\Internet Explorer" -ValueName Version

If you don’t specify the Subkey value, you will receive an error message:

£> Get-RegistrySTRING -Hive HKLM -SubKey -ValueName Version

Get-RegistrySTRING : Missing an argument for parameter 'SubKey'. Specify a parameter of type 'System.String' and try again.

At line:1 char:31

+ Get-RegistrySTRING -Hive HKLM -SubKey -ValueName Version

+                               ~~~~~~~

    + CategoryInfo          : InvalidArgument: (:) [Get-RegistrySTRING], ParameterBindingException

    + FullyQualifiedErrorId : MissingArgument,Get-RegistrySTRING

If you don’t specify the parameter at all, you get a different error message:

£> Get-RegistrySTRING -Hive HKLM  -ValueName Version

Get-RegistrySTRING : Invalid parameter

At line:1 char:1

+ Get-RegistrySTRING -Hive HKLM  -ValueName Version

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

    + CategoryInfo          : InvalidArgument: (StdRegProv:root\cimv2\StdRegProv) [Get-RegistrySTRING], CimException

    + FullyQualifiedErrorId : HRESULT 0x80041008,Get-RegistrySTRING

If you specify the SubKey but not the value you’ll get an error:

Get-RegistrySTRING -Hive HKLM  -SubKey "SOFTWARE\Microsoft\Internet Explorer"

sValue ReturnValue

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

                        1

Remember that a non-zero return code from a CIM method means that there has been an error.

A good way to discover examples of validation in CDXML modules is to view the files on a system running Windows 8 or Windows Server 2012 (or later versions). You’ll find the examples in the subfolders of C:\Windows\System32\WindowsPowerShell\v1.0\modules.

There are a lot of modules in these systems, and over 60% are created using CDXML. Here is a quick way to search for interesting examples:

Get-ChildItem -Path $pshome\modules -Filter *.cdxml -File -Recurse | Select-String -Pattern '*validate*' -SimpleMatch 

Here are some examples of using validation in CDXML that I discovered in this way:

<ValidateNotNull /> is similar to <ValidateNotNullOrEmpty />, which  you’ve seen already. I prefer to use <ValidateNotNullOrEmpty />.

To validate on a set of values:

                                <ValidateSet>

                                    <AllowedValue>Both</AllowedValue>

                                    <AllowedValue>Incoming</AllowedValue>

                                    <AllowedValue>Outcoming</AllowedValue>

                                </ValidateSet>

This is taken from C:\Windows\System32\WindowsPowerShell\v1.0\modules\Defender\MSFT_MpPreference.cdxml.

You can also validate on a range as shown in C:\Windows\System32\WindowsPowerShell\v1.0\modules\MMAgent\ps_mmagent_v1.0.cdxml:

                <ValidateRange Min="1" Max="8192" />

You might also find examples of other validation options, such as:

                <ValidateCount Min="1" Max="10" />

                <ValidateLength Min="1" Max="10" />

ValidatePattern and ValidateScript from advanced functions are not allowed in CDXML. You can have multiple validations on the same parameter, but remember that once one fails, that’s it—your input is rejected.

If you require them, you also have some options to allow specific scenarios:

                <AllowEmptyCollection />

                <AllowEmptyString />

                <AllowNull />

That’s it for today. Tomorrow I’ll finish this short series with a look at some of the issues that arise when you start working with registry data types other than strings.

Bye for now.

We invite you to follow The Scripting Guys on Twitter and Facebook. If you have any questions, send an email to The Scripting Guys at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. Until then, remember eat your cmdlets every day with a dash of creativity.

Richard Siddaway, Windows PowerShell MVP and Honorary Scripting Guy

PowerTip: Override Modules in PowerShell Session

$
0
0

Summary: Learn how to override the modules you have imported into your Windows PowerShell session.

Hey, Scripting Guy! Question How can I re-load the Windows PowerShell module that I am developing so I can test the changes at each
           stage of development?

Hey, Scripting Guy! Answer By default, if you have a module loaded into to your Windows PowerShell session and you attempt to re-load it,
           nothing happens because Import-Module discovers it is already loaded. Use the –Force parameter to ensure
           that a fresh copy of the module is loaded and you get your latest features:

Import-Module <mymodule> -Force

Registry Cmdlets: Complete the Registry CDXML Module

$
0
0

Summary: Richard Siddaway shows how to complete the registry CDXML module.

Honorary Scripting Guy, Richard Siddaway, here today filling in for my good friend, The Scripting Guy. This is the final post in a series. To catch up, read:

So far, you’ve seen how to create a CDXML module with a single cmdlet based on the GetStringValue method of the StdRegProv CIM class. In this post, I’ll show you how to add the other methods that are available in the class to create a complete module of easy-to-use cmdlets for working with the registry. I’ll also show you how to work with some of the more awkward registry data types.

The complete module consists of these cmdlets:

Get-RegistryBinary

Get-RegistryDWORD

Get-RegistryExpandSTRING

Get-RegistryKey

Get-RegistryMultiSTRING

Get-RegistryQWORD

Get-RegistrySTRING

Get-RegistryValue

New-RegistryKey

Remove-RegistryKey

Remove-RegistryValue

Set-RegistryBinary

Set-RegistryDWORD

Set-RegistryExpandSTRING

Set-RegistryMultiSTRING

Set-RegistryQWORD

Set-RegistrySTRING

These cmdlets provide the ability to get and set values for each of the registry data types, get lists of registry keys and values, create new keys, and delete keys and values.

Reading data from the registry is very useful, but you also need to be able to write to the registry. You can use the SetStringValue method as an example:

      <Cmdlet>

        <CmdletMetadata Verb="Set" Noun="RegistrySTRING" ConfirmImpact="Low"/>

        <Method MethodName="SetSTRINGvalue">

          <ReturnValue>

            <Type PSType="System.UInt32"/>

            <CmdletOutputMetadata>

            </CmdletOutputMetadata>

          </ReturnValue>

         

          <Parameters>

            <Parameter ParameterName="hDefKey" >

              <Type PSType="RSPSNA.Registry.Hive" />

              <CmdletParameterMetadata IsMandatory="true" PSName="Hive">

              </CmdletParameterMetadata>

            </Parameter>

            <Parameter ParameterName="sSubKeyName" >

              <Type PSType="System.String" />

              <CmdletParameterMetadata PSName="SubKey">

                <ValidateNotNullOrEmpty />

              </CmdletParameterMetadata>

            </Parameter>

            <Parameter ParameterName="sValueName" >

              <Type PSType="System.String" />

              <CmdletParameterMetadata PSName="ValueName">

                <ValidateNotNullOrEmpty />

              </CmdletParameterMetadata>

            </Parameter>

            <Parameter ParameterName="sValue">

              <Type PSType="System.String"  />

              <CmdletParameterMetadata PSName="Value">

                <ValidateNotNullOrEmpty />

              </CmdletParameterMetadata>

            </Parameter>

          </Parameters>

        </Method>

      </Cmdlet>

In this case, you have to provide the hive, subkey, and value with the data to insert into that value. I’ve used ValueName and Value for the registry value and data respectively:

Set-RegistryString -Hive HKLM -SubKey SOFTWARE\ModuleTest -ValueName svalue -Value 'Summit2014'

The cmdlet will create the registry value if it doesn’t exist but the key needs to be present already. You can create registry keys as follows:

New-RegistryKey -Hive HKLM -SubKey software\moduletest

Other registry data types include:

  • Binary
  • DWORD – 32-bit number
  • QWORD – 64-bit number
  • Multistting = array of strings
  • Expanding string (usually used with environment variables)

When you look at registry values by using the EnumValues method, the output isn’t very easy to work with:

£> [uint32]$hklm = 2147483650

£> $key = 'software\moduletest'

£> Invoke-CimMethod -ClassName StdRegProv -MethodName EnumValues -Arguments @{hDefKey = $hklm; sSubKeyName = $key}

ReturnValue    : 0

sNames         : {dvalue, qvalue, svalue, mstring...}

Types          : {4, 11, 1, 7...}

PSComputerName :

You get an array of value names in sNames plus an array of data types in Types. The data types (as occurs so often in CIM) are coded as integer values. Ideally, you would want to see the data types output in a friendlier manner.

You can apply a similar technique to the way the numeric values for registry hives were dealt with. Start by creating an enumeration:

    <Enum EnumName="RSPSNA.Registry.Type" UnderlyingType="System.UInt32">

      <Value Name="String" Value="1" />

      <Value Name="ExpandingString" Value="2" />

      <Value Name="Binary" Value="3" />

      <Value Name="Dword" Value="4" />

      <Value Name="MultiString" Value="7" />

      <Value Name="Qword" Value="11" />

    </Enum>

Remember that the name part of the enumeration cannot contain spaces. If you need to break words, use capital letters to designate the start of words or use a delimiter (such as a hyphen).

The CDXML definition for the cmdlet created from the EnumValues method looks like this:

      <Cmdlet>

        <CmdletMetadata Verb="Get" Noun="RegistryValue" ConfirmImpact="Low"/>

        <Method MethodName="EnumValues">

          <ReturnValue>

            <Type PSType="System.UInt32"/>

            <CmdletOutputMetadata>

            </CmdletOutputMetadata>

          </ReturnValue>

         

          <Parameters>

            <Parameter ParameterName="hDefKey" >

              <Type PSType="RSPSNA.Registry.Hive" />

              <CmdletParameterMetadata IsMandatory="true" PSName="Hive">

              </CmdletParameterMetadata>

            </Parameter>

            <Parameter ParameterName="sSubKeyName" >

              <Type PSType="System.String" />

              <CmdletParameterMetadata PSName="SubKey">

                <ValidateNotNullOrEmpty />

              </CmdletParameterMetadata>

            </Parameter>

            <!-- Two output arrays -->

            <!--                   -->

            <Parameter ParameterName="sNames">

              <Type PSType="System.String[]"  />

              <CmdletOutputMetadata />

            </Parameter>

            <Parameter ParameterName="Types">

              <Type PSType="RSPSNA.Registry.Type[]" />

              <CmdletOutputMetadata />

            </Parameter>

          </Parameters>

        </Method>

      </Cmdlet>

You have two output arguments. The first is sNames, which is an array of strings that contain the value names. The second is an array that is created with the RSPSNA.Registry.Type enumeration supplying the values. You still have the issue of two output arrays, when ideally, you want one set of output objects. Unfortunately, CDXML can’t solve this issue, but a little bit of Windows PowerShell magic gives you the answer.

Using the cmdlet as-is results in this output:

£> Get-RegistryValue -Hive HKLM -SubKey software\moduletest

sNames      : {dvalue, qvalue, svalue, mstring...}

Types       : {Dword, Qword, String, MultiString...}

ReturnValue : 0

You can see that Types now contains the data type names rather than the numeric values. This would be usable for a registry key with only a handful of values, but ideally, you want something easier to read:

£> $values = Get-RegistryValue -Hive HKLM -SubKey software\moduletest

£> 0..$($values.sNames.Length-1) | foreach {New-Object -TypeName psobject -Property @{'Name'=$values.sNames[$psitem]; 'Type'=$values.Types[$psitem]}} | ft -a

Name               Type

----               ----

dvalue            Dword

qvalue            Qword

svalue           String

mstring     MultiString

SZvalue ExpandingString

Bvalue           Binary

If you store the output from Get-RegistryValue in a variable, you can access each array individually. Pipe numeric values that match the array indices – 0 to $values.sNames.Length-1 into Foreach-Object. Within the Foreach, use New-Object to create a PSObject that combines the matching name and data type. Output and use Format-Table to display, if you prefer.

By the way, don’t go looking for a Software\ModuleTest key in the HKLM hive on your system. It’s something I created for demonstration purposes.

Working with the integer data types, DWORD and QWORD, is similar to working with strings. The only change is that the output (or value input) property becomes a System.UInt32 or System.UInt64 respectively, and the name changes to uValue.

The MultiString data type holds an array of strings rather than a single string. The parameters working with the data are defined as an array, for instance:

            <Parameter ParameterName="sValue">

              <Type PSType="System.String[]"  />

              <CmdletOutputMetadata />

            </Parameter>

The remaining CDXML code is very similar to that for dealing with single string values. You can use the standard Windows PowerShell array handling techniques to work with the data.

To read the data:

$data = Get-RegistryMultiSTRING -Hive HKLM -SubKey SOFTWARE\ModuleTest -ValueName mstring  | select -ExpandProperty svalue

To remove a value from the array and write back:

$data = $data | where {$psitem -ne 'Value2'}

Set-RegistryMultiSTRING -Hive HKLM -SubKey SOFTWARE\ModuleTest -ValueName mstring  -Value $data

Get-RegistryMultiSTRING -Hive HKLM -SubKey SOFTWARE\ModuleTest -ValueName mstring

To add another value into the array and write back:

$data += 'Value6'

Set-RegistryMultiSTRING -Hive HKLM -SubKey SOFTWARE\ModuleTest -ValueName mstring  -Value $data

Get-RegistryMultiSTRING -Hive HKLM -SubKey SOFTWARE\ModuleTest -ValueName mstring

To reset the whole array:

$data = 'Value1', 'Value2', 'Value3'

Set-RegistryMultiSTRING -Hive HKLM -SubKey SOFTWARE\ModuleTest -ValueName mstring  -Value $data

Environment variables are some of those background pieces of functionality that no one really notices until they go wrong. They can be used in the registry. The data type is known as an expanding string (sounds like something from astrophysics), and you can use the cmdlets from your registry module like this:

Get-RegistryExpandSTRING -Hive HKLM -SubKey software\moduletest -ValueName SZvalue

Set-RegistryExpandSTRING -Hive HKLM -SubKey software\moduletest -ValueName SZvalue -Value '%TEMP%\mynewfolder'

Reading is just like reading a simple string value, but the result looks like this:

sValue

------

C:\windows\TEMP\myfolder

Notice that the result is automatically expanded for you. If you want to modify or create a registry value by using an environment variable, you code it like this:

'%TEMP%\mynewfolder'

The registry stores the data in that format until it’s accessed, at which point, the accessing routine should perform the expansion.

The last registry data type is the Binary type. I don’t like modifying these because bad things can happen if you get it wrong. But if you have to make changes, the safest way is to use the Set-RegistryBinary cmdlet from your module.  

CIM treats the binary data as an array of unsigned 8-bit integers. You need to convert this to a byte array for Windows PowerShell (.NET). The output argument when working with the GetBinaryValue method is coded like this:

            </Parameter>

            <Parameter ParameterName="uValue">

              <Type PSType="System.Byte[]"  />

              <CmdletOutputMetadata />

            </Parameter>

Reading data from binary registry values can be accomplished like this:

£> $values = Get-RegistryBinary -Hive HKLM -SubKey software\moduletest -ValueName Bvalue  | select -ExpandProperty uvalu

e

£> $values

0

1

2

3

4

5

6

12

Modifying binary data can be accomplished by changing the array and writing back:

£> $values += [byte]14

£> Set-RegistryBinary -Hive HKLM -SubKey software\moduletest -ValueName Bvalue -Value $values

0

A return code of 0 indicates success.

Using CDXML isn’t a technique for everyone. One issue is that there aren’t any good tools to make it easier to work with. The XML is relatively simple, but you need to be careful and precise in your coding. There are many modules in the later versions of Windows that are created by using CDXML.

You can use the technique to create similar modules on earlier versions of Windows by using existing CIM classes. For instance, the Win32_NetworkAdapter and Win32_NetworkAdapterConfiguration classes could be used to duplicate the NetAdapter and NetTCPIP modules respectively. If you have those modules installed on your down-level systems, and you use the same cmdlet names, you could manage all of your systems from what appears to be the same set of cmdlets.

This concludes my series about registry cmdlets. If you are interested in learning more about CDXML, my talk on this topic is available. Please see the PowerShell Summit North America 2014 site on YouTube. To download the slides, demo scripts, and code for each stage of module development (including the final version of the module), see my Dropbox site.

Bye for now.

Biography

Richard Siddaway is based out of the UK. He spends his time automating anything and everything, for Kelway, Ltd. A 7-year Windows PowerShell MVP, Richard is a prolific blogger, mainly about Windows PowerShell (see Richard Siddaway's Blog). Richard has been a director at PowerShell.org since the inception of that organization, and he is a frequent speaker at Windows PowerShell user groups and conferences. He has written a number of books: PowerShell in Practice, PowerShell and WMI, PowerShell in Depth (co-author), PowerShell Dive (co-editor), and Learn Active Directory Management in a Month of Lunches, which features lots of Windows PowerShell. All of the books are available from Manning Publications.

We invite you to follow The Scripting Guys on Twitter and Facebook. If you have any questions, send an email to The Scripting Guys atscripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. Until then, remember eat your cmdlets every day with a dash of creativity.

Richard Siddaway, Windows PowerShell MVP and Honorary Scripting Guy

PowerTip: Use PowerShell to Install Modules on Your System

$
0
0

Summary: Learn how to use Windows PowerShell to install modules on your system.

Hey, Scripting Guy! Question How can I use Windows PowerShell to roll out a new set of modules that are used extensively in my organization?

Hey, Scripting Guy! Answer When Windows PowerShell 5.0 is available, you can use PowerShellGet against an internal repository
           to install your modules.

  For systems running Windows PowerShell 4.0 or earlier, create a central repository of modules on a network share
  and use a scheduled task to check for updated modules. Then copy any new or updated modules to your system.

Use PowerShell DSC to Configure the Registry

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell and Desired State Configuration to configure the registry.

Microsoft Scripting Guy, Ed Wilson, is here. I thought I would piggy-back a bit on the excellent posts that Windows PowerShell MVP, Richard Siddaway, wrote this week about working with the registry with Windows PowerShell.

If I want to make sure that a registry entry exists (or does not exist), I can use Windows PowerShell Desired State Configuration (DSC). Another advantage to using DSC is that it automatically updates, so I do not need to worry if the entry will still be there at a later point in time.

Using DSC to configure the use of biometrics

I decided that I wanted to disable the use of biometric devices for sign in to my system. To do this, there are several registry keys available that work in conjunction with Group Policy. The thing is that I do not want to fool around with using Group Policy. In fact, I have heard from many IT pros that the Group Policy teams in their organizations are reluctant to make changes they request.

Note  DSC runs in a system context, and therefore, it does not have access to the current user registry hive (HKCU).

On to my configuration script...

The first thing I do is use the Configuration keyword and specify a name for my configuration. I then specify my node—I am using LocalHost, so I do not need to worry about a computer name. I then specify the registry resource, and a name. I specify that I want the registry key to exist, so I specify that I will ensure it is present. I provide the registry key, the key name, the value, and the type of value. This portion of the script is shown here:

Configuration SetBiometrics {

    Node localhost {

    Registry DisableBiometrics {

        Ensure = "Present"

        Key = "HKLM:\SOFTWARE\Policies\Microsoft\Biometrics"

        ValueName = "Enabled"

        ValueData = "0"

        ValueType = "Dword" }

The other two registry sections are pretty much the same. In fact, I pasted the script from my previous section and made minor changes. Here are the other two parts of the configuration script:

Registry DisableCredentials {

        Ensure = "Present"

        Key = "HKLM:\SOFTWARE\Policies\Microsoft\Biometrics\Credential Provider"

        ValueName = "Enabled"

        ValueData = "0"

        ValueType = "Dword" }

    Registry DisableDomainCredentials {

        Ensure = "Present"

        Key = "HKLM:\SOFTWARE\Policies\Microsoft\Biometrics\Credential Provider"

        ValueName = "Domain Accounts"

        ValueData = "0"

        ValueType = "Dword" } }}

The last thing I need to do is to call my configuration like I would a function. I pass a directory for my output. I then use Start-DSCConfiguration and specify the path to the MOF file. This command is shown here:

SetBiometrics -output C:\clientConfig

Start-DscConfiguration -Path C:\clientConfig -Wait -Force -Verbose

Here is the complete script as it appears in my Windows PowerShell ISE:

Image of command output

Because I called Start-DSCConfiguration with the –Verbose parameter, I can see everything that is going on, in addition to how long it takes to run the configuration. In the output in the following image, I see that the registry key did not exist, and therefore, it was created.

Image of command output

That is all there is to it. Now Windows PowerShell DSC will make sure the registry keys exist and that they are set the way I want them set. To be sure, I open Regedit to see if the keys were created. As you see here, they were:

Image of menu

That is all there is to using Windows PowerShell DSC to set registry keys and values. This also concludes Registry Week. Join me tomorrow when Microsoft PFE and Honorary Scripting Guy, Ian Farr, continues his RODC series.

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 Registry Keys

$
0
0

Summary: Learn how to use Windows PowerShell to display registry keys.

Hey, Scripting Guy! Question How can I use Windows PowerShell to provide a list of registry keys that I can filter, instead of using Regedit to search?

Hey, Scripting Guy! Answer Use the Get-ItemProperty cmdlet and point it to a specific registry hive. The following command looks for
           software and Microsoft on the HKLM drive. It uses the psChildName property to display the registry key names.

Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\* | select pschildname

Weekend Scripter: Use PowerShell to Delegate Administrator of RODCs

$
0
0

Summary: Microsoft PFE, Ian Farr, discusses using Windows PowerShell to delegate administrator of RODC.

Microsoft Scripting Guy, Ed Wilson, is here. Today we have Honorary Scripting Guy and Microsoft PFE, Ian Farr, back for more words of wisdom...

Welcome to the third post in a four part series about securing and managing read-only domain controllers (RODCs). I like to think of this collection of posts as "organic"—they only became a series after the green shoots of the first two posts were already well established!

The first post discussed a function that analyses RODC authentication. The function reports on accounts that are authenticated by an RODC that aren’t revealed (that is, the account password or secret is not stored on the RODC). It helps you manage your password replication policies. For the full write up, see Use PowerShell to Work with RODC Accounts.

The second post discussed a function that checks whether a user is a member of a high-privileged group. It can be used in conjunction with the first function to see if your RODCs have authenticated high-privileged users. This helps identify and remove a potential means of compromising Active Directory. To read that post, see Use PowerShell to Search Active Directory for High-Privileged Accounts.

Today’s post discusses a function that allows you to delegate the administration of an RODC. The function adds a user or a group to the ManagedBy attribute of the computer account for the RODC. This grants the user or group members local administrative privileges on the RODC.

Note  Users delegated as RODC administrators should not be a member of any privileged groups in Active Directory because this negates the protections that an RODC provides. Furthermore, the accounts used for delegated administration should be "secondary logon accounts" that are used only for RODC administration. For example, they should not be accounts that are also used to log on to workstations for typical user activity, such as Internet browsing or reading email.

Here’s the function: Set-ADRodcManagedByAttribute

Let’s take a look…

The function has two parameters: Rodc and Principle.

Rodc This parameter determines the RODC on which the ManagedBy attribute is set. It can accept a value from the pipeline, so we can pipe a list of RODCs into the function. There’s also some parameter validation to ensure that we are dealing with an RODC. If the domain controller object has the IsReadOnly attribute set to True, we know we have an RODC.

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

[ValidateScript({(Get-ADDomainController -Identity $_).IsReadOnly})]

[String]$Rodc

Principal This parameter defines the user or group that is added to the ManagedBy attribute. It has to be a DistinguishedName. The parameter validation uses the –Identity parameter of Get-ADObject, which only accepts a distinguished name and will check whether the user or group exists in Active Directory. The ManagedBy attribute should be populated with a domain local group.

[parameter(Mandatory,Position=2)]

[ValidateScript({Get-ADObject -Identity $_})]

[String]$Principal

The function has a Begin statement block to perform further validation before each RODC object is processed. In the following script, we check that the object supplied to the Principal parameter is a User or Group object. If it isn’t, we Break out of the function.

     Begin {

        #Get the supplied AD Object

        $ADObject= Get-ADObject -Identity $Principal -ErrorAction SilentlyContinue

 

        #Check that $Principal is a user or group

        If (($ADObject.ObjectClass -ne "user") -and ($ADObject.ObjectClass -ne "group")) {

 

            #Write a message to the host

            Write-Host "$Principal is not a user or group"

            Break

        }  

     }  

Next, we enter the Process statement block. We iterate through each RODC that is passed into the function and use the Get-ADComputer and Set-ADObject cmdlets to update the ManagedBy attribute. On the associated computer account object, to our user or group DistinguishedName, the -Replace parameter makes use of a hash table that references our user or group principal.

Process {

#Set the ManagedBy attribute

Get-ADComputer -Identity $Rodc | Set-ADObject -Replace @{ManagedBy = $Principal}

}  

Here’s an example of how to use the function:

Get-ADDomainController -Filter {IsReadOnly -eq $True} |

Set-ADRodcManagedByAttribute -Principal "CN=RODC Admins,OU=Groups,DC=Fabrikam,DC=com"

In this command, we get all of the RODCs for the current domain and pipe them into the Set-ADRodcManagedByAttribute function. This updates the ManagedBy attribute of each corresponding computer object to the distinguished name of the RODC Admins domain local group. Of course, we could also pipe a specific list of RODCs into the function to meet a particular administrative requirement, or simply run the function by itself against a single RODC.

And that’s it. Next time out, I’ll talk about synchronizing our delegated RODCs administrators’ passwords to their respective RODCs.

~Ian

Thanks, Ian. Join us tomorrow when Ian returns for the final part of this series.

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 Network Adapters Not Bound to TCP/IP

$
0
0

Summary: Use Windows PowerShell to find network adapters that are not bound to TCP/IP.

Hey, Scripting Guy! Question I am troubleshooting a computer that will not connect to the network, and I suspect the protocol bindings.
           How can I find network adapters that are not bound to TCP/IP?

Hey, Scripting Guy! AnswerUse the Get-NetAdapterBinding Windows PowerShell function, filter on a display name of TCP,
           and see if the protocol is enabled, for example:

Get-NetAdapterBinding -DisplayName *tcp* | where {!($_.enabled)}

Weekend Scripter: Use PowerShell to Synchronize Delegated Admin Passwords

$
0
0

Summary: Microsoft PFE and Honorary Scripting Guy, Ian Farr, discusses using Windows PowerShell to synchronize delegated administrator passwords.

Microsoft Scripting Guy, Ed Wilson, is here. Guest blogger and Honorary Scripting Guy, Ian Farr, is back with us today for the conclusion of his series about read-only domain controllers (RODCs)...

Welcome to the final post in my semi-spontaneous series about managing and securing RODCs.

The first post discussed a function that analyses RODC authentication. The function reports on accounts that are authenticated by an RODC that aren’t revealed (that is, the account password or secret is not stored on the RODC). It helps you manage your password replication policies. For the full write up, see Use PowerShell to Work with RODC Accounts.

The second post discussed a function that checks whether a user is a member of a high-privileged group. It can be used in conjunction with the first function to see if your RODCs have authenticated high-privileged users. This helps identify and remove a potential means of compromising Active Directory. To read that post, see Use PowerShell to Search Active Directory for High-Privileged Accounts.

The third post discussed a function that assists in ensuring that we have low-privileged users delegated as RODC administrators. It populates the RODCs ManagedBy attribute with a designated User or Group. It can easily propagate administrative privilege to a large number of RODCs. Here is that post: Use PowerShell to Delegate Administrator of RODCs.

On to the last post...

This one discusses a function that synchronizes the passwords of our previously delegated administrators.

Why do such a thing?

Without access to an read-write domain controller (RWDC), an RODC is unable to authenticate users or computers if their passwords aren't already stored on the RODC. Here's a scenario:

  • An RODC becomes isolated (unable to communicate with a RWDC).
  • A delegated admin needs to do some work on the isolated RODC.
  • The delegated admin has never previously logged on to the RODC.
  • The delegated admin's password has never been prepopulated.

In this scenario, the delegated admin would not be able to get into the RODC until connectivity with a RWDC is resumed. If the admin's password had been prepopulated, the admin could have performed the work.

How does the function work?

The function uses functionality that was introduced in 2012 with the Active Directory Replication cmdlets—namely, the –PasswordOnly parameter of the Sync-ADObject cmdlet. However, before we get to that bit, we need to enumerate the ManagedBy attribute of the RODC’s computer object and check whether we are dealing with a user or group:

$ManagedByPrincipal= Get-ADComputer -Identity $Rodc -Property ManagedBy |
ForEach-Object {Get-ADObject -Identity $_.ManagedBy}

The value in ManagedBy is a DistinguishedName, so we can then use Get-ADObject to retrieve an object and store it in $ManagedByPrincipal. With this variable populated, we check the ObjectClass to see if we are dealing with a user object, a group object, or something else:

If (($ManagedByPrincipal.ObjectClass-ne "user") -and ($ManagedByPrincipal.ObjectClass -ne "group")) {

#Write a message to the host

Write-Host "$ManagedByPrincipal is not a user or group"

}   #End of If (($ManagedByPrincipal.ObjectClass-ne "user") -and ($ManagedByPrincipal.ObjectClass -ne "group"))

Else {...}

If we are dealing with a user or group, we now determine the exact ObjectClass in the Else script block. We use the Switch statement to check if we have a user or a group object. If a group is found, we enumerate the members and store the results in $Principals. If a user is found, we assign our original $ManagedByPrincipal to $Principals:

Switch ($ManagedByPrincipal.ObjectClass) {

"group" {

#Hold the enumerated ManagedBy group members in $Principals

$Principals = Get-ADGroupMember -Identity $ManagedByPrincipal -Recursive

}   #End of "group"

"user" {

#Hold single ManagedBy principal in $Principals (user object)

$Principals = $ManagedByPrincipal

}   #End of "user"      

}  

Finally, we loop through each element of $Principals and execute the following script, which synchronizes the user’s password to our RODC:

$Principals | ForEach-Object {

Get-ADObject -Identity $_.distinguishedName |

Sync-ADObject -Destination $Rodc -PasswordOnly -PassThru

}  

In this script, we get an object that represents the current iteration of $Principals with the Get-ADObject cmdlet and pipe that into the Sync-ADObject cmdlet with our RODC as the destination. The –PasswordOnly parameter synchronizes only the password, as you’d expect.

The function’s –Rodc parameter accepts pipeline input, so we can run a one-liner like this to sync the passwords to a number of RODCs:

            Get-ADDomainController -Filter {IsReadOnly -eq $True} | Sync-ADRodcManagedByPassword

    Note You should synchronize the passwords of delegated RODC administrative accounts on a regular basis, so that the RODCs have up-to-date passwords.

That’s it for the series…for now, anyway! We’ve looked at four functions to assist with the administration of RODCs:

I’ve put the functions from the series into a fledgling module to expedite their usage:
RODC Management PowerShell Module

I've also applied the functions in the following sample script, which produces CSV reports of RODC authentication and high privileged use:
Create RODC Password Replication Policy and High Privileged Usage Reports

TTFN!
~Ian

Thanks for this series on RDOC, Ian!  It has been a great and useful series. 

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 Routing

$
0
0

Summary: Use Windows PowerShell to display networking routing information.

Hey, Scripting Guy! Question How can I use Windows PowerShell to display information about network connectivity issues related to
           the routing table on my server and permit me to sort the output?

Hey, Scripting Guy! Answer Use the Get-NetRoute Windows PowerShell function, and sort by interface index, nexthop, or other properties,
           for example:

Get-NetRoute | sort ifindex

Don’t Learn PowerShell, Use PowerShell

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about getting started with Windows PowerShell.

Hey, Scripting Guy! Question Hey, Scripting Guy! I get it. I need to learn Windows PowerShell—I see it mentioned everywhere. The problem is that I don’t have five years to learn the stuff. And besides that, by the time that five years has passed, you guys will probably come out with at least two new versions of Windows PowerShell. So if I spend five years trying to learn Windows PowerShell 4.0, by the time I am done learning it, I will still be three or four versions behind. I feel like I can never catch up—like a hamster running around on a wheel. I never seem to make any progress. What can I do?

—GM

Hey, Scripting Guy! Answer Hello GM,

Microsoft Scripting Guy, Ed Wilson, is here. I just got back from the gym. Luckily, the gym I go to is open 24 hours a day, so I can get up early and get back to still start my day. I kind of know what you are talking about. I did three miles on the treadmill this morning—and in the end, I never really moved an inch of distance.

GM, I can see what you are talking about, but you are basing your argument on a false argument. You do not need to learn everything there is about Windows PowerShell to use it. In fact, the vast majority of IT pros never write a single Windows PowerShell script. The difference between Windows PowerShell and VBScript (or some other scripting language) is that Windows PowerShell is not only a scripting language. In fact, it is possible to use Windows PowerShell without learning Windows PowerShell at all. This is because Windows PowerShell is an interactive environment in addition to a scripting language. Your problem has given me a good reason to introduce Don't Learn PowerShell Week.

Windows PowerShell ISE: Not only for scripts

The Windows PowerShell ISE is not only for writing scripts. In fact, I use it nearly all the time. The reason is that it is a great interactive console, and if I have more than a single command I want to type, I can move to the script pane, type my commands, and then run them. I do not have to write a script. The Windows PowerShell ISE is shown here:

Image of Windows PowerShell ISE

The upper white box is the script pane. The bottom blue box is the interactive Windows PowerShell console. It is also where the output from the script pane appears. The right pane is the Command Add-on. By default, when the Windows PowerShell ISE first launches, the Command Add-on appears. If I close it by clicking the “X” in the upper-right corner of the Command Add-on or by clearing the Show Command Add-on menu item (as shown in the following image), the next time I launch the Windows PowerShell ISE, the Command Add-on does not open. If I later decide that I want the Command Add-on, I select Show Command Add-on in the View menu.

Image of menu

What good is the Command Add-on anyway?

The Command Add-on is a great tool because it permits me to build commands on the fly. It also permits me to find Windows PowerShell cmdlets without knowing anything about the cmdlet name or about Windows PowerShell verbs or nouns. For more experienced Windows PowerShell users, it is a great tool to use when demonstrating to beginners how Windows PowerShell works.

First find the command

Obviously, the first thing to do is find the appropriate Windows PowerShell command. Windows PowerShell commands are often cmdlets—as in a little command. Notice that by default, the Modulestext box is set to All. If I know what module contains the command I want to use, I can select that module from the drop-down list. But when starting out, I would not even know what a module is, and I would definitely not know which module might contain the command I am interested in using. So I leave Modulesset to All, and I begin typing in the Nametext box. As I type, the cmdlets filter out until I am left with only a few cmdlets, as shown here:

Image of Windows PowerShell ISE

I look at the commands, and I see that some of them contain the word VMProcessor. I might guess that it has something to do with a virtual machine (because of the letters VM). Other commands, such as Debug-Process, Start-Process, and Stop-Process appear to be self-explanatory: Debug-Process probably has something to do with debugging a process, and Start-Process and Stop-Process probably permit me to start or stop a process.

One of the nice things about Windows PowerShell is most of the cmdlet names tend to make sense. (This is unlike the old-fashioned type of command names, such as SC, which seem to have very little relationship to anything.)

If I select the Get-Process cmdlet from the filtered Command window, the bottom pane immediately changes to display the parameters for Get-Process. This is shown here:

Image of Windows PowerShell ISE

Each parameter set (ways of using the cmdlet) appears on a different tab. The default is Name, and it appears as the one that is automatically selected. I can add the target ComputerName. I can also choose to display file versioning or module information by selecting the FileVersionInfo or Module options. In addition, I can limit the information that is returned to a specific process by entering the process name in the Nametext box.

When I have completed my selections, I have three choices. I can run the command immediately and display the output from the command by pressing the Run button. This is shown here:

Image of Windows PowerShell ISE

Alternatively, if I press the Insert button, the command appears in the interactive Windows PowerShell command window, but it does not execute. This permits me to make changes to the command, or to add additional commands to the command line prior to running the command.

In the following image, I have cleared the output from the previous command by pressing the Window wiper, squeegee, which is located on the Add-ons menu. Notice that the Get-Process command appears on the first line in the Windows PowerShell console, but it has not yet run.

Image of Windows PowerShell ISE

If I want the command in the script pane, I need to click the Copy button to place the command on the clipboard. I then paste it into the script pane at the appropriate location. This is shown here:

Image of Windows PowerShell ISE

So, by using the Windows PowerShell Command Add-on pane, I can easily find, create, and execute Windows PowerShell commands on the fly without having an in-depth knowledge of Windows PowerShell.

GM, that is all there is to using the Show-Command command. Don’t Learn PowerShell Week will continue tomorrow when I will talk about more cool stuff.

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

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Find PowerShell Commands

$
0
0

Summary: Learn how to easily find Windows PowerShell commands.

Hey, Scripting Guy! Question How can I use Windows PowerShell if I do not know the appropriate command to use or the available options?

Hey, Scripting Guy! Answer In the Windows PowerShell console, type Show-Command. In the dialog box that appears, type what you need—
           such as process or service name. The appropriate Windows PowerShell commands appear, and you can select
           and run the command you need.

Viewing all 3333 articles
Browse latest View live


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