Introduction to Microsoft PowerShell – Working with PSDrives and Items

PowerShell provides many ways to work with files and with other sorts of structured data it treats as files. Typically as shown before we can use the same commands as in cmd.exe but they parameters change also we can call many using he names of commands found in Unix type systems, these are aliases for PowerShell cmdlets so as to make the transition to PowerShell easier for administrators. Let have a look at the common commands used to manage files and their aliases. Do not worry to much on the manipulation commands used since I will cover those later in other blog posts but do take a look at what those aliases map to:

PS C:\> Get-Alias | where {$_.definition -match "path|item|content|location"} | Group-Object definition

Count Name                      Group
----- ----                      -----
    1 Add-Content               {ac}
    3 Get-Content               {cat, gc, type}
    3 Set-Location              {cd, chdir, sl}
    1 Clear-Content             {clc}
    1 Clear-Item                {cli}
    1 Clear-ItemProperty        {clp}
    3 Copy-Item                 {copy, cp, cpi}
    1 Copy-ItemProperty         {cpp}
    1 Convert-Path              {cvpa}
    6 Remove-Item               {del, erase, rd, ri...}
    3 Get-ChildItem             {dir, gci, ls}
    1 Get-Item                  {gi}
    2 Get-Location              {gl, pwd}
    1 Get-ItemProperty          {gp}
    1 Invoke-Item               {ii}
    3 Move-Item                 {mi, move, mv}
    1 Move-ItemProperty         {mp}
    1 New-Item                  {ni}
    1 Pop-Location              {popd}
    1 Push-Location             {pushd}
    2 Rename-Item               {ren, rni}
    1 Rename-ItemProperty       {rnp}
    1 Remove-ItemProperty       {rp}
    1 Resolve-Path              {rvpa}
    1 Set-Content               {sc}
    1 Set-Item                  {si}
    1 Set-ItemProperty          {sp}

As we can see in addition to the commands that we know from Unix type systems and those we use from cmd.exe we can find that PowerShell provides even more aliases for those cmdlets and for other actions we will discuss we will see that it has it’s own aliases and cmdlets.

PSDrives

Lets start with the concept that PowerShell treats files and folders as Items, the reason for this is that PowerShell treats other structure data as a file systems and calls the mappings to them PSDrives. To list the PSDrives on our current system we use the cmdlet Get-PSDive:

PS C:\> Get-PSDrive | ft -AutoSize

Name     Used (GB) Free (GB) Provider    Root               CurrentLocation
----     --------- --------- --------    ----               ---------------
Alias                        Alias
C            60.13    535.94 FileSystem  C:\
cert                         Certificate \
D           764.70    166.81 FileSystem  D:\
E           617.89    313.62 FileSystem  E:\
Env                          Environment
F                            FileSystem  F:\
Function                     Function
G                            FileSystem  G:\
H                            FileSystem  H:\
HKCU                         Registry    HKEY_CURRENT_USER
HKLM                         Registry    HKEY_LOCAL_MACHINE
I                            FileSystem  I:\
J                            FileSystem  J:\
Variable                     Variable
WSMan                        WSMan

As we can see in addition to the normal drives we have on the system we have others drives we can navigate to:

  • Alias – Represent all aliases valid for the current PowerShell Session.
  • Cert – Certificate store for the user represented in Current Location.
  • Env – All environment variables for the current PowerShell Session.
  • Function - All functions available for the current PowerShell Session.
  • HKLM - Registry HKey Local Machine Registry Hive.
  • HKCU - Registry HKey Current User Hive for the user the PowerShell session is running as.
  • WSMan - WinRM (Windows Remote Management) configuration and credentials.

Each of these PowerShell Drives are dependent on what is called PowerShell Providers that allow the access to the structured information. These can be listed with the Get-PSProvider cmndlet:

PS C:\> Get-PSProvider | ft -AutoSize

Name        Capabilities                Drives
----        ------------                ------
WSMan       Credentials                 {WSMan}
Alias       ShouldProcess               {Alias}
Environment ShouldProcess               {Env}
FileSystem  Filter, ShouldProcess       {C, D, E, F...}
Function    ShouldProcess               {Function}
Registry    ShouldProcess, Transactions {HKLM, HKCU}
Variable    ShouldProcess               {Variable}
Certificate ShouldProcess               {cert}

As we can see there are provider for other types other than FileSystem, this can me extended depending on PowerShell modules loaded and installed on a system for example on Windows 7 systems with the Remote Administration Tools or Windows 2008 R2 Domain Controller the can have access to an Active Directory provider, machines with the VMware PowerCLI installed will have access to providers for VMware Datastore and Virtual Infrastructures:

PowerCLI C:\> Get-PSProvider

Name                 Capabilities                  Drives
----                 ------------                  ------
WSMan                Credentials                   {WSMan}
Alias                ShouldProcess                 {Alias}
Environment          ShouldProcess                 {Env}
FileSystem           Filter, ShouldProcess         {C, A, D}
Function             ShouldProcess                 {Function}
Registry             ShouldProcess, Transactions   {HKLM, HKCU}
Variable             ShouldProcess                 {Variable}
Certificate          ShouldProcess                 {cert}
VimDatastore         ShouldProcess                 {vmstores, vmstore}
VimInventory         Filter                        {vis, vi}

Using one of this providers is quite simple, for it we use the New-PSDrive cmdlet, options for the cmdlet may change depending on the provider used so if using any external provide do look at the documentation provided by the company that made the provider. Each provider has different capabilities and this capabilities dictate what can be done on the data that is accessed, for example:

  • ShouldProcess - Cmdlets that support the -Confirm and -WhatIf parameter can be used against the PSDrive.
  • Credentials - Cmdlets that use the -Credential parameter can be used against the PSDrive
  • Transactions - Cmdlets can me executed in a transactional fashion and use the parameter -UseTransaction against the PSDrive.
  • Filter - Cmdlets can use wildcard filtering for enumerating objects using the -Filter parameter against the PSDrive.

Lets map a drive:

PS C:\Users\carlos> New-PSDrive -Name isostore -Root \\192.168.1.2\isostore -PSProvider filesystem

Name           Used (GB)     Free (GB) Provider      Root                      CurrentLocation
----           ---------     --------- --------      ----                      ---------------
isostore                               FileSystem    \\192.168.1.2\isostore

PS C:\Users\carlos> ls isostore:


    Directory: \\192.168.1.2\isostore


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
da---         1/26/2012  12:49 PM            Oracle
da---         3/27/2012   1:11 PM            Microsoft
da---         3/15/2012   7:34 PM            Linux
da---        12/30/2011   3:49 PM            FreeBSD
da---         3/15/2012   7:33 PM            Solaris
d----         12/2/2011  11:29 AM            unlock-all-v102
da---         3/15/2012   7:34 PM            VMWare
da---         2/27/2012   8:04 AM            Apple
-a---         2/24/2012   9:51 PM 3589316608 8250.0.WINMAIN_WIN8BETA.120217-1520_X64FRE_SERVER_EN-US-HB1_SSS_X64FRE_EN-
                                             US_DV5.ISO
-a---          1/4/2012   2:06 PM        403 shutdown_vms.rb
-a---         4/13/2011   3:17 AM  531705856 openfileresa-2.99.1-x86_64-disc1.iso
-a---         10/8/2007   4:06 PM  661127168 win2k3entsp2.iso
-a---        12/30/2011   7:32 PM  115838976 pfSense.iso
-a---          1/2/2012  11:16 PM  533204992 XenServer-6.0.0-install-cd.iso
-a---          1/4/2012   1:50 PM        177 shtdown.sh
-a---          5/4/2011   5:42 PM  369717248 VMware-VMvisor-Installer-4.0.0.Update01-208167.x86_64.iso

One thing that we need to keep in mind is that the drives we create are only present in the current PowerShell Session only and only can be accessed by the session so Windows Explorer and other tools on windows will not have access to the drive. Also as we can see in the example we can use a longer name for the drive than the letters we are used to use on Windows when mapping drives.

Working with Items

Listing Items

Lets look first at listing the contents of the current working folder for this we will use the Get-ChildItem cmdlet:

PS C:\> Get-ChildItem


    Directory: C:\


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         7/13/2009  11:20 PM            PerfLogs
d-r--          4/5/2012  10:27 PM            Program Files
d-r--          4/8/2012   6:39 PM            Program Files (x86)
d----          4/5/2012   7:42 PM            Python27
d----          4/5/2012   7:41 PM            Python32
d----          4/5/2012   7:38 PM            Ruby193
d----          4/6/2012  12:27 PM            SysinternalsSuite
d-r--          4/5/2012  10:54 PM            Users
d----          4/8/2012  11:14 AM            Windows
-a---          4/5/2012  10:32 PM       1024 .rnd

As we can see we get a listing of the files and folders and basic information about them. Each item is in fact a .Net object of System.IO.FileInfo type that we can manipulate. Lets try searching in a given path for a file that matches a wild card, as we saw before when talink about PSProviders the FileSystem provider allows for filtering. Lets search for any file that starts with telnet in my install of Ruby 1.9.3:

PS C:\> Get-ChildItem -Path .\Ruby193 -Recurse -Filter telnet*


    Directory: C:\Ruby193\lib\ruby\1.9.1\net


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         5/18/2011   9:07 PM      32598 telnet.rb

Creating Files and Folders

Lets crate a directory and file for us to use to keep exploring the cmdlets, lets start by using the New-Item cmdlet to create a folder called testfolder:

PS C:\> New-Item -Path . -Name testfolder -ItemType "directory"


    Directory: C:\


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----          4/9/2012  11:45 AM            testfolder

As with all cmdlets I mention on the blog posts I do recommend that you look at full help of the command and look at the members of the objects returned as covered in the initial blogposts.

Now lets create a file, for this we will use the ItemType of "file" to indicate we want a file.

PS C:\> New-Item -Path .\testfolder -Name testfile -ItemType "file"


    Directory: C:\testfolder


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---          4/9/2012  11:53 AM          0 testfile

 

Working with Items

Now that we have a file we can work with lets look at the properties and methods available with the Get-Item cmdlet:

PS C:\> Get-Item -Path .\testfolder\testfile | Get-Member


   TypeName: System.IO.FileInfo

Name                      MemberType     Definition
----                      ----------     ----------
Mode                      CodeProperty   System.String Mode{get=Mode;}
AppendText                Method         System.IO.StreamWriter AppendText()
CopyTo                    Method         System.IO.FileInfo CopyTo(string destFileName), System.IO.FileInfo CopyTo(s...
Create                    Method         System.IO.FileStream Create()
CreateObjRef              Method         System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
CreateText                Method         System.IO.StreamWriter CreateText()
Decrypt                   Method         System.Void Decrypt()
Delete                    Method         System.Void Delete()
Encrypt                   Method         System.Void Encrypt()
Equals                    Method         bool Equals(System.Object obj)
GetAccessControl          Method         System.Security.AccessControl.FileSecurity GetAccessControl(), System.Secur...
GetHashCode               Method         int GetHashCode()
GetLifetimeService        Method         System.Object GetLifetimeService()
GetObjectData             Method         System.Void GetObjectData(System.Runtime.Serialization.SerializationInfo in...
GetType                   Method         type GetType()
InitializeLifetimeService Method         System.Object InitializeLifetimeService()
MoveTo                    Method         System.Void MoveTo(string destFileName)
Open                      Method         System.IO.FileStream Open(System.IO.FileMode mode), System.IO.FileStream Op...
OpenRead                  Method         System.IO.FileStream OpenRead()
OpenText                  Method         System.IO.StreamReader OpenText()
OpenWrite                 Method         System.IO.FileStream OpenWrite()
Refresh                   Method         System.Void Refresh()
Replace                   Method         System.IO.FileInfo Replace(string destinationFileName, string destinationBa...
SetAccessControl          Method         System.Void SetAccessControl(System.Security.AccessControl.FileSecurity fil...
ToString                  Method         string ToString()
PSChildName               NoteProperty   System.String PSChildName=testfile
PSDrive                   NoteProperty   System.Management.Automation.PSDriveInfo PSDrive=C
PSIsContainer             NoteProperty   System.Boolean PSIsContainer=False
PSParentPath              NoteProperty   System.String PSParentPath=Microsoft.PowerShell.Core\FileSystem::C:\testfolder
PSPath                    NoteProperty   System.String PSPath=Microsoft.PowerShell.Core\FileSystem::C:\testfolder\te...
PSProvider                NoteProperty   System.Management.Automation.ProviderInfo PSProvider=Microsoft.PowerShell.C...
Attributes                Property       System.IO.FileAttributes Attributes {get;set;}
CreationTime              Property       System.DateTime CreationTime {get;set;}
CreationTimeUtc           Property       System.DateTime CreationTimeUtc {get;set;}
Directory                 Property       System.IO.DirectoryInfo Directory {get;}
DirectoryName             Property       System.String DirectoryName {get;}
Exists                    Property       System.Boolean Exists {get;}
Extension                 Property       System.String Extension {get;}
FullName                  Property       System.String FullName {get;}
IsReadOnly                Property       System.Boolean IsReadOnly {get;set;}
LastAccessTime            Property       System.DateTime LastAccessTime {get;set;}
LastAccessTimeUtc         Property       System.DateTime LastAccessTimeUtc {get;set;}
LastWriteTime             Property       System.DateTime LastWriteTime {get;set;}
LastWriteTimeUtc          Property       System.DateTime LastWriteTimeUtc {get;set;}
Length                    Property       System.Int64 Length {get;}
Name                      Property       System.String Name {get;}
BaseName                  ScriptProperty System.Object BaseName {get=if ($this.Extension.Length -gt 0){$this.Name.Re...
VersionInfo               ScriptProperty System.Object VersionInfo {get=[System.Diagnostics.FileVersionInfo]::GetVer...

For getting properties for the file object we have several ways to achive this first one is using the Get-ItemProperty cmdlet by given as the name the object property:

PS C:\> Get-ItemProperty -Path .\testfolder\testfile -Name LastAccessTime

PSPath         : Microsoft.PowerShell.Core\FileSystem::C:\testfolder\testfile
PSParentPath   : Microsoft.PowerShell.Core\FileSystem::C:\testfolder
PSChildName    : testfile
PSDrive        : C
PSProvider     : Microsoft.PowerShell.Core\FileSystem
LastAccessTime : 4/9/2012 11:53:25 AM

Another Method we can use is to get the object and just request it, lets look at some properties that security professionals will find quite interesting:

PS C:\> (Get-Item -Path .\testfolder\testfile).LastWriteTime

Monday, April 09, 2012 11:53:25 AM


PS C:\> (Get-Item -Path .\testfolder\testfile).LastAccessTime

Monday, April 09, 2012 11:53:25 AM


PS C:\> (Get-Item -Path C:\Windows\System32\aaclient.dll).VersionInfo

ProductVersion   FileVersion      FileName
--------------   -----------      --------
6.1.7600.16385   6.1.7600.1638... C:\Windows\System32\aaclient.dll

Just like other shell we can redirect output of commands as text to files using > and >> symbols:

  • cmdlet > filename - Redirect command output to a file and overwrite content.
  • cmdlet >> filename - append into a file
  • cmdlet 2> filename - Redirect Errors from operation to a file and overwrite content.
  • cmdlet 2>> filename - Append errors to a file
  • cmdlet 2>&1 - Add errors to output
  • cmdlet 1>&2 - Add output to errors

Lets look also at the Add-Content cmdlet:

PS C:\> Add-Content -Path C:\testfolder\testfile -Value (get-date)
PS C:\> Get-Content -Path C:\testfolder\testfile
4/9/2012 3:39:29 PM

Lets work with the object method to modify the file, in this case we will use EFS to encrypt the file on NTFS, lets start with checking if the file is encrypted:

PS C:\> (Get-Item -Path .\testfolder\testfile).attributes
Archive

Now lets encrypt the file and see if its encrypted:

PS C:\> (Get-Item -Path .\testfolder\testfile).encrypt()
PS C:\> (Get-Item -Path .\testfolder\testfile).attributes
Archive, Encrypted

We can even confirm using the cipher.exe command:

PS C:\> cipher.exe /c .\testfolder\testfile

 Listing C:\testfolder\
 New files added to this directory will not be encrypted.

E testfile
  Compatibility Level:
    Windows XP/Server 2003

  Users who can decrypt:
    infidel01\Carlos [Carlos(Carlos@infidel01)]
    Certificate thumbprint: 45F5 3D35 94B0 3C47 B727 AB63 0198 F19A 2793 1283

  No recovery certificate found.

  Key Information:
    Algorithm: AES
    Key Length: 256
    Key Entropy: 256

Lets Rename an item with the Rename-Item cmdlet:

PS C:\> Rename-Item -Path C:\testfolder -NewName test_folder
PS C:\> ls


    Directory: C:\


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         7/13/2009  11:20 PM            PerfLogs
d-r--          4/5/2012  10:27 PM            Program Files
d-r--          4/8/2012   6:39 PM            Program Files (x86)
d----          4/5/2012   7:42 PM            Python27
d----          4/5/2012   7:41 PM            Python32
d----          4/5/2012   7:38 PM            Ruby193
d----          4/6/2012  12:27 PM            SysinternalsSuite
d----          4/9/2012   4:44 PM            test_folder
d-r--          4/5/2012  10:54 PM            Users
d----          4/8/2012  11:14 AM            Windows
-a---          4/5/2012  10:32 PM       1024 .rnd

 

Lets delete the file we have been using for the examples:

PS C:\> Remove-Item -Path C:\test_folder\testfil
PS C:\> ls .\test_folder


    Directory: C:\test_folder


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---          4/9/2012   3:39 PM         21 testfile


PS C:\>  Remove-Item -Path C:\test_folder\testfile
PS C:\> ls .\test_folder

Working with Paths

Lets look at working with paths, we will firs start with defining the difference of Path and LiteralPath in the parameters of several commands. This is a source of confusion for many people learning PowerShell on their own by exploring the shell cmdlets. When working with a file system on a drive or share Powershell Windows restricts the characters that can be used for a file name, like *, ?, /, $ and others since they are use for variable expansion and wildcard search but since PowerShell lets us work with Active Directory, Certificate Store, Registry and others that do not have the same restrictions as the file system. This is why we use -Path when we want the special characters treated as wildcards and -LiteralPath for those cases where those special characters are part of the item names. An example of expansion:

PS C:\> Set-Location -Path Perf*
PS C:\PerfLogs>

We can see as wildcards where used to match the path. To get the current location of where we are in a provider we use the Get-Location cmdlet:

PS C:\PerfLogs> Get-Location

Path
----
C:\PerfLogs

To Change locations we use the Set-Location cmdlet:

PS C:\PerfLogs> Set-Location C:\testfolder
PS C:\testfolder> Get-Location

Path
----
C:\testfolder

We can take a path and add a child item to the path with Join-Path cmdlet:

PS C:\> Join-Path -Path C:\Windows -ChildPath system
C:\Windows\system

We can also have it join a path using wildcards:

PS C:\> Join-Path -Path C:\Win* -ChildPath tem* -Resolve
C:\Windows\Temp

We can also give it a list of path to append a child object to:

PS C:\> join-path -path c:\windows,c:\python,c:\ruby  -ChildPath temp
c:\windows\temp
c:\python\temp
c:\ruby\temp

Some time we will find our self with path that we obtained from a property of an object and we may need to extract parts of the path, for this we will use the Split-Path cmdlet and we can get different pats of the paths depending of what we want:

PS C:\> split-path c:\windows\secret.txt
c:\windows
PS C:\> split-path c:\windows\secret.txt -Qualifier
c:
PS C:\> split-path c:\windows\secret.txt -NoQualifier
\windows\secret.txt
PS C:\> split-path c:\windows\secret.txt -Parent
c:\windows
PS C:\> split-path c:\windows\secret.txt -Leaf
secret.txt

It also supports extracting parts from other types of paths:

PS C:\> Split-Path -Path /var/log/tftp.log -Leaf
tftp.log
PS C:\> Split-Path -Path /var/log/tftp.log -Parent
\var\log
PS C:\> split-path -Path /index.html -Qualifier
http:
PS C:\> split-path -Path /index.html -NoQualifier
//www.darkoperator.com/index.html

We can test if a path exists:

PS C:\> test-path -path HKLM:\Software\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell
True
PS C:\> test-path -path C:\Windows
True
PS C:\> test-path -path C:\Windows\system32\aaclient.dll
True

As we can see this works with both files, folders and even other paths in other providers. Lets say we want to test is the path is for a File or a Folder, for this we will use Container for Folder and Leaf for File:

PS C:\> test-path -path C:\Windows\system32\aaclient.dll -PathType leaf
True
PS C:\> test-path -path C:\Windows\system32\aaclient.dll -PathType container
False

Conclusion

I invite you to keep exploring in the registry, variables and other psdrives available and learning what is possible and not and the differences in the parameters we can use with this providers. As always I hope this blog post is useful and informative.

Introduction to Microsoft PowerShell– Basics of Running Cmdlets

PowerShell Cmdlets

You will notice that for the PowerShell commands I use the word Cmdlet, that is how Microsoft calls and spells the word. In a PowerShell shell you can execute regular windows commands in addition to the cmdlets and most work without any problem some may experience problems depending on the parameters used since PowerShell uses space as a delimiter so do keep this in mind when you are running local exe files.

PowerShell cmdlets are in the form of a <verb>-<noun>, you will see common verbs like set, get, clear, write and stop to name a few and each belong to a group of actions, you can get an updated list of verbs at the TechNet site http://social.technet.microsoft.com/wiki/contents/articles/4537.powershell-approved-verbs-en-us.aspx do keep this list handy because if you create any module, cmdlet or function you should follow the naming so as to not confuse users and not get warnings from PowerShell when loading modules or cmdlets. To get a list of cmdlets on PS we use the Get-Command cmdlet:

image 

  When ran with no options we get a list of all cmdlet, functions and Aliases we have available. Just like on a Unix shell you will notice you have functions and aliases at your disposal to call. Aliases are mainly for saving time when entering commands and to make others more familiar when ran in a shell like the ls or the cat commands:

PS C:\Users\Carlos Perez> ls
    Directory: C:\Users\Carlos Perez
Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d-r--         2/16/2012   3:03 PM            Contacts
d-r--         3/26/2012  11:23 PM            Desktop
d-r--         2/16/2012   3:03 PM            Documents
d-r--          3/8/2012   3:52 PM            Downloads
d-r--         2/16/2012   3:03 PM            Favorites
d-r--         2/16/2012   3:03 PM            Links
d-r--         2/16/2012   3:03 PM            Music
d-r--         2/16/2012   3:03 PM            Pictures
d-r--         2/16/2012   3:03 PM            Saved Games
d-r--         2/16/2012   3:03 PM            Searches
d-r--         2/16/2012   3:03 PM            Videos
-a---         3/28/2012   8:16 PM         28 hello.txt
PS C:\Users\Carlos Perez> cat .\hello.txt
hello world
PS C:\Users\Carlos Perez> rm .\hello.txt
PS C:\Users\Carlos Perez> ls
    Directory: C:\Users\Carlos Perez
Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d-r--         2/16/2012   3:03 PM            Contacts
d-r--         3/26/2012  11:23 PM            Desktop
d-r--         2/16/2012   3:03 PM            Documents
d-r--          3/8/2012   3:52 PM            Downloads
d-r--         2/16/2012   3:03 PM            Favorites
d-r--         2/16/2012   3:03 PM            Links
d-r--         2/16/2012   3:03 PM            Music
d-r--         2/16/2012   3:03 PM            Pictures
d-r--         2/16/2012   3:03 PM            Saved Games
d-r--         2/16/2012   3:03 PM            Searches
d-r--         2/16/2012   3:03 PM            Videos

As we can see the aliases makes the shell behave similar to a Unix/Linux shell, but do keep in mind it is only similar, the parameters are not the same. 

One can use the tab key to auto complete PSDrive Paths (More on this on another blog post), File Paths,  Functions, Cmdlets, Function Options, Cmdlets Parameters, Variables and regular Windows Commands. So one can so Get-<tab> and keep hitting tab to cycle through the cmdlets available with the verb Get, the same can be done to find a cmdlet parameter like Get-Service –<tab>

The Get-Command also allow us to filter using wildcards:

PS C:\Users\Carlos Perez> Get-Command -Name *service* -CommandType cmdlet
CommandType     Name                                                Definition
-----------     ----                                                ----------
Cmdlet          Get-Service                                         Get-Service [[-Name] <String[]>] [-ComputerName ...
Cmdlet          New-Service                                         New-Service [-Name] <String> [-BinaryPathName] <...
Cmdlet          New-WebServiceProxy                                 New-WebServiceProxy [-Uri] <Uri> [[-Class] <Stri...
Cmdlet          Restart-Service                                     Restart-Service [-Name] <String[]> [-Force] [-Pa...
Cmdlet          Resume-Service                                      Resume-Service [-Name] <String[]> [-PassThru] [-...
Cmdlet          Set-Service                                         Set-Service [-Name] <String> [-ComputerName <Str...
Cmdlet          Start-Service                                       Start-Service [-Name] <String[]> [-PassThru] [-I...
Cmdlet          Stop-Service                                        Stop-Service [-Name] <String[]> [-Force] [-PassT...
Cmdlet          Suspend-Service                                     Suspend-Service [-Name] <String[]> [-PassThru] [...

On Windows 8 in PowerShell v3 we have the the Show-Command cmdlet that will bring a GUI Interface for exploring the cmdlet and it options allowing us to copy the command we build or run the command:

image

When we want to get specific help on any cmdlet we can use the get-help cmdlet or it’s alias help:

image

This will provide us with a base help for the cmdlet where we can see:

  • Name
  • Synopsis
  • Syntax
  • Description
  • Related Links
  • Remarks

We can use the –detail option to get more details on the options, their types and position in the command arguments if we pass each value without an option, we can also use the –examples to get example on how to use the cmdlet and a brief description of what the command is doing and we can get a with –full the entire content of the help message. You can consider help/Get-Help as the man command in Unix/Linux. When you look at the Syntax section the options you can quickly determine what values you can provide to them. When we see the message we will see that each optional Parameter we can pass is between [ ], if a parameter is not optional it will not be enclosed in [ ], some options do not require values those are just –<Parametername> other will take a value, for those that take a value PS will let you know the value type if it is a string, integer, object ..etc between <>, some can take a list of values and you will notice those will be in the format of <type[]>  and those that have a predefined list of options that can be given to a parameter will be in the format of < option1 | option2 | option3>.  I highly recommend that when starting with a cmdlet for the first time to use the –full parameter when getting help. The full help message will provide us additional information for each parameter as shown bellow:

 -Name <string[]>
     Specifies the service names of services to be retrieved. Wildcards are permitted. By default, Get-Service gets
     all of the services on the computer.
     Required?                    false
     Position?                    1
     Default value
     Accept pipeline input?       true (ByValue, ByPropertyName)
     Accept wildcard characters?  true
 -RequiredServices [<SwitchParameter>]
     Gets only the services that this service requires.
     This parameter gets the value of the ServicesDependedOn property of the service. By default, Get-Service gets a
     ll services.
     Required?                    false
     Position?                    named
     Default value                False
     Accept pipeline input?       false
     Accept wildcard characters?  false

As it can be seen for the –Name parameter we can see additional information like if it is required or not, the position when calling the cmdlet, this means that the cmdlet will take the first thing given to it an use it as the value for this parameter when the parameter is not given, we can also see it accepts inputs from the pipeline and that this can be a value or a property. In the case of the RequiredServices  parameter the position is named, that means that the name of the parameter must be specified with the value.

If the computer you are running PowerShell on has internet connectivity you can give the parameter–online to the Get-Help cmdlet to open a browser window with the latest help information for it.

Let take a look at the Get-Service cmdlet:  

image

As we can see we in syntax we can call the cmdlet in 3 different ways, one where we start by providing the name or names of the service, another where we provide Display Names and a third where we pass service controller objects (Remember PowerShell cmdlets output objects). Let look at the first one:

Get-Service [[-Name] <string[]>] [-ComputerName <string[]>] [-DependentServices] [-Exclude <string[]>] [-Include <string[]>] [-RequiredServices] [<CommonParameters>]

As we can see the –Name parameter takes a list of strings. Lets get the state of several services:

PS C:\Users\Carlos Perez> Get-Service -Name BITS, VSS
Status   Name               DisplayName
------   ----               -----------
Running  BITS               Background Intelligent Transfer Ser...
Stopped  VSS                Volume Shadow Copy

Now we ask for a full help for the command we will see for the name option that it accepts wildcard characters for the parameter of -Name and for the parameter of –DisplayName  so we can search for any service with the word WMI in its Display Name:

PS C:\Users\Carlos Perez> Get-Service -DisplayName *WMI*
Status   Name               DisplayName
------   ----               -----------
Stopped  wmiApSrv           WMI Performance Adapter

The Wildcard Characters that can be used are shown in the table bellow:

Wildcard Character Description Example

*

Matches zero or more characters, starting at the specified position

a*

?

Matches any character at the specified position

?n

[ ]

Matches a range of characters

[a-l]name

[ ]

Matches the specified characters

[bc]name

 

In PowerShell one can use parameter abbreviation, similar to what one can do with commands on Cisco IOS we only need to enter enough of the parameter name that is is unique against the other. In the Get-Process cmdlet the only parameter that starts with the letter N is Name so we can shorten it to only this letter:

PS C:\Users\Carlos Perez> Get-Process -N *vm*
Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    270      20     8956       7708    87            1392 vmtoolsd
    289      23    15252      14388   145   113.97   2544 vmtoolsd
     68       9     3444       3148    68     0.55   2532 VMwareTray

As we play with parameters and comandlets one of the things we can do is to maintain a transcript. We can do this with the Start-Transcript cmdlet, this will save all of our commands and output to a file and when we issue the cmdlet Stop-Transcript it will stop recording our action, we can even append to an existing file by giving it the –Append parameter. One thing to note is that you can not use it on ISE.

PS C:\Windows\system32> Start-Transcript C:\windows\Temp\testtranscript.txt
Transcript started, output file is C:\windows\Temp\testtranscript.txt
PS C:\Windows\system32> Get-Service | select -first 1
Status   Name               DisplayName
------   ----               -----------
Stopped  AeLookupSvc        Application Experience
PS C:\Windows\system32> Get-process | select -first 1
Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
     23       4     2128       1460    38     0.09    408 cmd
LogName: PS C:\Windows\system32> Stop-Transcript
Transcript stopped, output file is C:\windows\Temp\testtranscript.txt

Now as mentioned before PowerShell cmdlets return objects and we can pipe this objects to other cmdlets. We can illustrate by saving an object in to a variable and looking at what we have available. In PowerShell variables start with with $ In this example we will look at the object for the BITS service:

PS C:\Windows\system32> $srv = Get-Service -Name BITS
PS C:\Windows\system32> $srv
Status   Name               DisplayName
------   ----               -----------
Running  BITS               Background Intelligent Transfer Ser...

If we want to know it’s type we can use the .Net method of gettype()

PS C:\Windows\system32> $srv.GetType().fullname
System.ServiceProcess.ServiceController

If we want to look at the methods (actions that can be taken) and Properties (Information) of an object we can use the Get-Members cmdlet.

PS C:\Windows\system32> Get-Member -InputObject $srv
   TypeName: System.ServiceProcess.ServiceController
Name                      MemberType    Definition
----                      ----------    ----------
Name                      AliasProperty Name = ServiceName
RequiredServices          AliasProperty RequiredServices = ServicesDependedOn
Disposed                  Event         System.EventHandler Disposed(System.Object, System.EventArgs)
Close                     Method        System.Void Close()
Continue                  Method        System.Void Continue()
CreateObjRef              Method        System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
Dispose                   Method        System.Void Dispose()
Equals                    Method        bool Equals(System.Object obj)
ExecuteCommand            Method        System.Void ExecuteCommand(int command)
GetHashCode               Method        int GetHashCode()
GetLifetimeService        Method        System.Object GetLifetimeService()
GetType                   Method        type GetType()
InitializeLifetimeService Method        System.Object InitializeLifetimeService()
Pause                     Method        System.Void Pause()
Refresh                   Method        System.Void Refresh()
Start                     Method        System.Void Start(), System.Void Start(string[] args)
Stop                      Method        System.Void Stop()
ToString                  Method        string ToString()
WaitForStatus             Method        System.Void WaitForStatus(System.ServiceProcess.ServiceControllerStatus desi...
CanPauseAndContinue       Property      System.Boolean CanPauseAndContinue {get;}
CanShutdown               Property      System.Boolean CanShutdown {get;}
CanStop                   Property      System.Boolean CanStop {get;}
Container                 Property      System.ComponentModel.IContainer Container {get;}
DependentServices         Property      System.ServiceProcess.ServiceController[] DependentServices {get;}
DisplayName               Property      System.String DisplayName {get;set;}
MachineName               Property      System.String MachineName {get;set;}
ServiceHandle             Property      System.Runtime.InteropServices.SafeHandle ServiceHandle {get;}
ServiceName               Property      System.String ServiceName {get;set;}
ServicesDependedOn        Property      System.ServiceProcess.ServiceController[] ServicesDependedOn {get;}
ServiceType               Property      System.ServiceProcess.ServiceType ServiceType {get;}
Site                      Property      System.ComponentModel.ISite Site {get;set;}
Status                    Property      System.ServiceProcess.ServiceControllerStatus Status {get;}

 

We can also pipe the contents of the variable to the the cmdlet like so $srv | Get-Members as we can see we can get information like status, type, dependencies and we can take actions like pause , start and stop. we can also use tab completion to cycle thru the methods and properties of an object when it is in a variable.

Lets stop the service and get it’s status before and after:

PS C:\Windows\system32> (Get-Service -Name BITS).status
Stopped
PS C:\Windows\system32> (Get-Service -Name BITS).start()
PS C:\Windows\system32> (Get-Service -Name BITS).status
Running

You will notice that methods are always called with ( )  in the end since a methods takes parameters, properties we can call directly and they are the state of when the object was created that is why we execute the command and work with the object directly by running the command between parenthesis. 

Also properties and the results from methods can have methods and more properties beneath them, we can chain this to get the value or results we want.

PS C:\Windows\system32> $srv.Status.GetType()
IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     ServiceControllerStatus                  System.Enum

Another way would be to use the refresh method:

PS C:\Windows\system32> $srv.Status
Running
PS C:\Windows\system32> $srv.Stop()
PS C:\Windows\system32> $srv.Refresh()
PS C:\Windows\system32> $srv.Status
Stopped

As you can see one of the main advantages of PowerShell is the is the advantage to manipulate the data as objects and not as text. In the next post I will cover more on how to work with several objects, how to modify the objects and piping.

As always I hope you find this post informative and useful.

Introduction to Microsoft PowerShell – What is it and Setup

What Is PowerShell

I do believe that one of the biggest skills that both Administrator and Security Professional should have is to be able to automate tasks on a systems they are responsible for. Many old Unix long bearded veterans say that admins are lazy and they script and automate tasks because of that, I see it as being smart, we are taking tasks that could take hours and crunch it down to seconds, we reduce risk by making sure an action is repeatable and we learn in the process of automating making us better. So I decided to start a series of blog post and do an introduction on one of my favorite scripting languages which is Microsoft PowerShell.

PowerShell as the name implies is a shell first, a scripting language second. Microsoft a long time ago did a study on areas that they considered they where week and needed improvement and one of this was the ability to automate and administer a system thru a shell. Microsoft designed and came with what I consider a rather unique approach in PowerShell and that is a Object Model based shell. Most shells in Linux, Unix and even cmd.exe shell in Windows are text driven where each command returns it’s out put in strings, in PowerShell the output of each command or cmdlet as it is called in PowerShell is a .Net Object that we can then use in many unique ways.  The grammar is based originally on the POSIX Shell grammar and then evolved and expanded by adding concepts from Perl, Python, VBScript and C#.

Setting Up the Environment

Depending our version of Windows are the steps we need to take to get PowerShell running on our system. On Windows system after Windows 7 and Windows Server 2008 R2 power shell comes built in, on Windows 2008 it i s a feature that needs to be installed from the feature available in server manager and on Windows Vista, Windows XP and Windows 2003 you will need to download the installer from the download section in http://www.microsoft.com/powershell and install the package. For this series I will be covering v2.0 of PowerShell and some of the new improvements that will come with v3.0.  One important thing to keep in mind is that PowerShell uses the .Net framework so running the latest version of .Net Framework will provide us the best flexibility and capabilities on the objects returned from the PowerShell commands.

You will notice the depending your platform and build you will have x86 and/or x64 versions of PowerShell console and PowerShell ISE (Interactive Scripting Environment), the shortcuts will be located in Windows XP, Windows 2003 and Windows Vista in  Start –> All Programs –>Windows PowerShell V2 and on more modern versions of Windows you will find it in Start –> All Programs –> Accessories –> Windows PowerShell in addition to this from a command prompt or from the run dialog box you can call powershell.exe for the console and powershell_ise.exe to launch the Integrated Scripting Environment.

The Console

One of the first things you will notice when you launch the console in your machine it will be a console screen with a Blue background and lightly yellow letters

image

I recommend that you customize even more the shortcut by doing a Right Click on the PowerSherll Symbol on the top left and selecting Properties

image

In Options increase Buffer Size so as to save more commands in the buffer and enable QuickEdit Mode and Insert Mode if not selected.

image

Under Layout we can adjust the With and the Height of our Screen Buffer to better accommodate our screen size and the amount of output history we want for scrolling  in the Console.

image

If a program line Exchange Server or VMware PowerCLI sets a separate shortcut for a console for use of their snapping we must also do the changes on those shortcuts also. If you run PowerShell by invoking the command via a command prompt or thru the Run dialog box you will be greeted with a screen like this one:

image

Easily confused with a command prompt and does not have any of the setting we set since those are for the shortcut it self. Since PowerShell is a component at setup none of those settings that come set by default are set because PowerShell reads the information from HKCU\Console for the user. To customize this I recommend you visit this page http://poshcode.org/2220 and copy and paste the PowerShell code shown there and paste it in a PowerShell prompt running as Administrator you can use the Windows Calculator in Scientific mode to set your values in the proper hex values and do the changes in notepad before running the commands. This will give you a console like the one you call from the shortcut in your programs menu. These changes can also be made on Windows 8 running PowerShell v3.

Console Keyboard Commands

Keyboard

Operation

Left/Right Arrow Keys Move the editing cursor one space each time thru the current command line.
Crtl+Left Arrow, Crtl+Right Arrow Keys Moves the editing cursor one word each time thru the current command line
Home Moves cursor to beginning of the current command line
End Moves cursor to the end of the current command line
Up/Down Arrow Keys Moves up and down thru the command history
Tab Does command and option completion
F7 Shows command history window that can be navigated with the Up and Down Arrow Keys, pressing Enter will execute the command selected in the window
Insert Key Toggles between character insertion and character overwrite mode
Delete Key Deletes a character under the editing cursor in the current command line
Backspace Key Deletes a character to the left of the editing cursor in the current command line

In the addition to the history command window one sees when pressing the F7 Key

image

One can use the Get-History cmdlet or the history alias for the command (More details on command and how to use the history command for generating scripts in blog posts to come) he command will return a list of the commands enter indexed with a number:

PS C:\Users\Carlos Perez> get-history
  Id CommandLine
  -- -----------
   1 dir
   2 Get-Process
   3 Get-Service
   4 Get-Command -Verb get
To recall one of the commands in the history one uses the # symbol and the number of the command an the press the tab key to pull the command from history to the current command line. 

 

Integrated Scripting Environment

Microsoft started including with PowerShell 2.0 the ISE (Integrated Scripting Environment) this is more than a script editor it also functions as as interactive shell and support plugins that can extend it’s functionality.

image

Some of the advantages of the ISE are:

  1. Multiple Script editing tabs.
  2. Use of easier editing and selection of command output.
  3. Color Syntax for PowerShell Scripts
  4. Remote PowerShell Session.
  5. Execution of selected PowerShell Code with F8
  6. Tab Completion for Command and Options

Microsoft greatly improved ISE in PowerShell v3 by adding IntelliSense just like in Visual Studio an improve command window that looks and behaves better and a command search pane:

image 

 

Conclusion

I invite you to play with settings for your console and ISE and get it to a point where you are confortable with the setup and appearance and also invite you to play a bit with the commands. In the next blog post we will go a little deeper in to the existing commands, loading modules and snapping, getting help and execution policy for scripts. 

Creating WMI Filters and GPOs with PowerShell

In my last 2 blog post I covered the creation of group policy objects for distributing certificates to all computers in a domain and enable Network Level Authentication on them plus also covered how to create and use WMI filters to specify which machines a Group Policy Object should apply to. On this blog post I will cover how to do this with Windows 2008 R2 built in PowerShell Module and some external ones from SDM Software. The GPO that we will be creating is to disable RDP on none Vista, Windows 7 and Windows 2008 hosts since following the other  blog posts these do not support NLA on their Remote Desktop Service. We will use PowerShell on a Windows 2008 R2 Domain Controller. Since we are going to use external scripts we would first start modifying the execution policy this is done by running the Set-ExecutionPolicy command to allow local scripts to execute without the need of being signed.

PS C:\Windows\system32> Set-ExecutionPolicy remotesigned
Execution Policy Change
The execution policy helps protect you from scripts that you do not trust. Changing the execution policy might expose
you to the security risks described in the about_Execution_Policies help topic. Do you want to change the execution
policy?
[Y] Yes  [N] No  [S] Suspend  [?] Help (default is "Y"): y
PS C:\Windows\system32>

As stated by the command this could be a potential security risk so do remember to re-run the command at the en with the execution policy of Restricted. Before we start creating group policy objects and linking them we should create a WMI Filter that we will attach to the policy. I took the liberty to write one based on another one I saw in the Microsoft Scripting Repository that will create a series of base filters for you when ran in a Domain Controller running Windows 2008 or Windows 2008 R2. You can download the script from my GitHub account at https://github.com/darkoperator/powershell_scripts/blob/master/create-wmifilters.ps1 the script will make the necessary changes to the registry to allow modification of attributes locally on the box thus allowing us to add the filters. The script is ran from a PoweShell Window providing the path like any other PowerShell script:

PS C:\Users\Administrator\Documents> .\create-wmifilters.ps1
Checking is registry key is set to allow changes to AD System Only Attributes is set.
Allow System Only Change key is not set
Creating key and setting value to 1
Starting creation of WMI Filters:
Adding WMI Filter for: Virtual Machines
Adding WMI Filter for: Workstation 32-bit
Adding WMI Filter for: Workstation 64-bit
Adding WMI Filter for: Workstations
Adding WMI Filter for: Domain Controllers
Adding WMI Filter for: Servers
Adding WMI Filter for: Windows 2000
Adding WMI Filter for: Windows XP
Adding WMI Filter for: Windows Vista
Adding WMI Filter for: Windows 7
Adding WMI Filter for: Windows Server 2003
Adding WMI Filter for: Windows Server 2008
Adding WMI Filter for: Windows Server 2008 R2
Adding WMI Filter for: Windows Vista and Windows Server 2008
Adding WMI Filter for: Windows Server 2003 and Windows Server 2008
Adding WMI Filter for: Windows 2000, XP and 2003
Finished adding WMI Filters
Disabling Allow System Only Change Attributes on server

Now you will have some WMI Filters we can use as base in our Group Policy Objects, do remember that we can have several filters linked to a single GPO.

Once this is done we can import the GroupPolicy PowerShell module that is installed on Windows 2008 Domain Controllers when promoted and look at the available commands we get from the module:

PS C:\> Import-Module grouppolicy
PS C:\> Get-Command -Module grouppolicy | Format-Table -AutoSize
CommandType Name                       Definition
----------- ----                       ----------
Cmdlet      Backup-GPO                 Backup-GPO -Guid <Guid> -Path <String> [-Comment <String>] [-Domain <String>]...
Cmdlet      Copy-GPO                   Copy-GPO -SourceGuid <Guid> -TargetName <String> [-SourceDomain <String>] [-T...
Cmdlet      Get-GPInheritance          Get-GPInheritance [-Target] <String> [-Domain <String>] [-Server <String>] [-...
Cmdlet      Get-GPO                    Get-GPO [-Guid] <Guid> [[-Domain] <String>] [[-Server] <String>] [-All] [-Ver...
Cmdlet      Get-GPOReport              Get-GPOReport [-Guid] <Guid> [-ReportType] <ReportType> [[-Path] <String>] [[...
Cmdlet      Get-GPPermissions          Get-GPPermissions -Guid <Guid> [-TargetName <String>] [-TargetType <Permissio...
Cmdlet      Get-GPPrefRegistryValue    Get-GPPrefRegistryValue -Guid <Guid> -Context <GpoConfiguration> -Key <String...
Cmdlet      Get-GPRegistryValue        Get-GPRegistryValue -Guid <Guid> -Key <String> [-ValueName <String>] [-Domain...
Cmdlet      Get-GPResultantSetOfPolicy Get-GPResultantSetOfPolicy [-Computer <String>] [-User <String>] -ReportType ...
Cmdlet      Get-GPStarterGPO           Get-GPStarterGPO -Guid <Guid> [-Domain <String>] [-Server <String>] [-All] [-...
Cmdlet      Import-GPO                 Import-GPO -BackupId <Guid> -Path <String> [-TargetGuid <Guid>] [-TargetName ...
Cmdlet      New-GPLink                 New-GPLink -Guid <Guid> -Target <String> [-LinkEnabled <EnableLink>] [-Order ...
Cmdlet      New-GPO                    New-GPO [-Name] <String> [-Comment <String>] [-Domain <String>] [-Server <Str...
Cmdlet      New-GPStarterGPO           New-GPStarterGPO [-Name] <String> [-Comment <String>] [-Domain <String>] [-Se...
Cmdlet      Remove-GPLink              Remove-GPLink -Guid <Guid> -Target <String> [-Domain <String>] [-Server <Stri...
Cmdlet      Remove-GPO                 Remove-GPO -Guid <Guid> [-Domain <String>] [-Server <String>] [-KeepLinks] [-...
Cmdlet      Remove-GPPrefRegistryValue Remove-GPPrefRegistryValue [[-Server] <String>] -Guid <Guid> -Context <GpoCon...
Cmdlet      Remove-GPRegistryValue     Remove-GPRegistryValue [-Guid] <Guid> [-Key] <String> [[-ValueName] <String>]...
Cmdlet      Rename-GPO                 Rename-GPO -Guid <Guid> -TargetName <String> [-Domain <String>] [-Server <Str...
Cmdlet      Restore-GPO                Restore-GPO -BackupId <Guid> -Path <String> [-Domain <String>] [-Server <Stri...
Cmdlet      Set-GPInheritance          Set-GPInheritance [-Target] <String> -IsBlocked <BlockInheritance> [-Domain <...
Cmdlet      Set-GPLink                 Set-GPLink -Guid <Guid> -Target <String> [-LinkEnabled <EnableLink>] [-Order ...
Cmdlet      Set-GPPermissions          Set-GPPermissions -Guid <Guid> -PermissionLevel <GPPermissionType> -TargetNam...
Cmdlet      Set-GPPrefRegistryValue    Set-GPPrefRegistryValue -Guid <Guid> -Context <GpoConfiguration> -Key <String...
Cmdlet      Set-GPRegistryValue        Set-GPRegistryValue -Guid <Guid> -Key <String> [-ValueName <String[]>] [-Valu...

We now use the New-GPO comandlet to create a new empty GPO named DisableRDP:

PS C:\> New-GPO -Name "DisableRDP"
DisplayName      : DisableRDP
DomainName       : acme-lab.com
Owner            : ACME-LAB\Domain Admins
Id               : 31122b47-5129-420f-9fe8-241584cc516d
GpoStatus        : AllSettingsEnabled
Description      :
CreationTime     : 3/20/2012 7:56:43 AM
ModificationTime : 3/20/2012 7:56:44 AM
UserVersion      : AD Version: 0, SysVol Version: 0
ComputerVersion  : AD Version: 0, SysVol Version: 0
WmiFilter        :

Now that we have a Group Policy Object created we can use the commadlet to create a registry reference in the GPO that will be applied to the machines that process the GPO under the context of Computer:

PS C:\> Set-GPPrefRegistryValue -Name DisableRDP -Key "HKLM\System\CurrentControlSet\Control\Terminal Server" -ValueName fDenyTSConnections -Value 1 -Type Dword -Context computer -Action update

Now to be able to link a WMI Filter to a GPO we need some external commands provided for free by SDM Software from http://www.sdmsoftware.com/products/freeware/ and we download the SDM GPMC PowerShell Cmdlets and install them on the Domain Controller. Once installed we can load the module:

PS C:\Users\Administrator\Documents> import-module SDM-GPMC

We want to use the Add-SDMWMIFilterLink command to link our GPO with one of the WMI Filters we created for the target of the GPO. To look at examples on how to use it we use the help command with the switch for examples:

PS C:\Users\Administrator\Documents> help Add-SDMWMIFilterLink -Examples
NAME
    Add-SDMWMIFilterLink
SYNOPSIS
    Adds a WMI Filter to a particular GPO
    --------------  Example 1 --------------
    C:\PS>Add-SDMWMIFilterLink "Wireless Policy" -FilterName "Laptop Test"
    Links the WMI filter called "Laptop Test" to the GPO called "Wireless Policy"
    Filter Laptop test linked to GPO Wireless Policy

As we can see the command is quite simple to use we just need to provide it a name for the GPO and a filter name to link to the GPO. Lets link now the GPO with the WMI Filter:

PS C:\Users\Administrator\Documents> Add-SDMWMIFilterLink "DisableRDP" -FilterName "Windows 2000, XP and 2003"
Filter Windows 2000, XP and 2003 linked to GPO DisableRDP

Once done we can now link the GPO to any part of our Active Directory structure. In this case I will attach it to the entire Forest of my lab AD infrastructure:

PS C:\Users\Administrator\Documents> New-GPLink -Name DisableRDP -Target "dc=acme-lab,dc=com”
GpoId       : 31122b47-5129-420f-9fe8-241584cc516d
DisplayName : DisableRDP
Enabled     : True
Enforced    : False
Target      : DC=acme-lab,DC=com
Order       : 3
DisplayName      : DisableRDP
DomainName       : acme-lab.com
Owner            : ACME-LAB\Domain Admins
Id               : 31122b47-5129-420f-9fe8-241584cc516d
GpoStatus        : AllSettingsEnabled
Description      :
CreationTime     : 3/20/2012 7:56:43 AM
ModificationTime : 3/20/2012 8:18:04 AM
UserVersion      : AD Version: 0, SysVol Version: 0
ComputerVersion  : AD Version: 1, SysVol Version: 1
WmiFilter        :
DisplayName      : DisableRDP
DomainName       : acme-lab.com
Owner            : ACME-LAB\Domain Admins
Id               : 31122b47-5129-420f-9fe8-241584cc516d
GpoStatus        : AllSettingsEnabled
Description      :
CreationTime     : 3/20/2012 7:56:43 AM
ModificationTime : 3/20/2012 7:56:44 AM
UserVersion      : AD Version: 0, SysVol Version: 0
ComputerVersion  : AD Version: 0, SysVol Version: 0
WmiFilter        :

This could be a very good way to automate the process of creating Group Policy Objects in lab and then move this to a production environment. Also you could use it for automating disaster recovery procedures.

As always I hope you found this blog post useful and informative.

WMI Filters in Group Policy Objects

One of the problems that we see every day in production environments is that even when we would like to have all machines on the same version of Windows many times this is not possible so we have to adapt our Group Policies to these environments. Microsoft provides a great way to check several parameters of the box thru Windows Management Instrumentation (WMI), this allows is from checking Hardware, software, patches and many other attributes available via the Windows Management Instrumentation (WMI). Lets say we want the previous Group Policy we created to apply only to Windows 2008 R2, Windows 2008, Vista and Windows 7 and lets also make a filter for Windows XP and 2003 so if we decide to make a filter to apply a policy to only those we can apply the filter. We start by going to the Group Policy  Management Console and choosing under the domain WMI Filters image We now Right Click an select New to create a new filter. We will get a screen where we will enter a name and a description for our first filter that will be for Windows 2008, Windows 2008R2, Windows Vista and Windows 7, the operating systems that support Network Level Authentication (NLA) on Remote Desktop Protocol (RDP). image Now we click on Add on the Queries section so as to add the WMI Query Language query we will use to filter to what Operating systems the policy is applied to: image We will select from Win32_OperatingSystem  the Version, this will give us a version number of 6.0 for Windows Vista and Windows 2008, 6.1 for Windows 2008 R2 and Windows 7. we will use:

SELECT * FROM Win32_OperatingSystem WHERE Version like "6.%"

We would click on Add type our filter and then just click on Ok:

image

We now click on save and the filter is ready to apply.

To apply a filter we just select the policy we want to apply the filter to and select from the WMI Filtering section the WMI Filter we want from the dropdown box:

image

In the case we wanted the filter to be for earlier supported versions of Windows we would use:

SELECT * FROM Win32_OperatingSystem WHERE Version LIKE "5.%"

If we wanted to even go more granular we could create separate filter for Product Type where:


  • ProductType 1 is for Client Versions of Windows
  • ProductType 2 is for Server Version of Windows operating as a Domain Controller
  • ProductType 3 for Server Version of Windows that are not a Domain Controller

If we wanted this to apply to all servers but not domain controller we could do a query like this one:

SELECT * FROM Win32_OperatingSystem WHERE (Version like "5.%" OR Version like "6.%") and ProductType<>2

As you can see there is a lot of flexibility with filters, specially since we can have several of them. As always I hope you find the post informative and useful.