Advanced Windows PowerShell Scripting Video Training

Advanced Windows PowerShell Scripting Video Training
Advanced Windows PowerShell Scripting Video Training

Monday, April 22, 2013

Remove files from external storage devices attached to your clients

This is one that is sure to upset a few users.  This project came from one of my PowerShell classes. The client had a strict policy that only company issued USB storage devices may be used on company computers. Group Policy can help keep that requirement enforced.  They also had a policy that described the files types that can be stored on these USB drivers. The problem is that users were storing files that were not of the approved type.  So, what can PowerShell do in this situation?

The code below allows the administrator to provide a list of computer names and a list of  file name patterns to look for.  They were particularly concerned about .exe files.  So the pattern for this would be “*.exe”.  Just be fore warned that code like this can be particularly upsetting to users.  Make sure that a well known acceptable usage policy is in place in your organization before unleashing this code on your people.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64


 

Function Remove-Contraband

{

[cmdletbinding()]

Param(

    [String[]]$ComputerName = "LocalHost",

    [String[]]$Pattern

)

    ForEach ($Client in $ComputerName)

    {

        Write-Host "Scanning: $Client" `

         -ForegroundColor Cyan `

         -BackgroundColor DarkCyan

        ForEach ($Item in $Pattern)

        {

 

            Try

            {

                $Files=(Get-WmiObject win32_logicalDisk `

                 -ComputerName $Client -ErrorAction Stop |

                 Where-Object {$_.DriveType -eq 2} |

                 Select-Object *,@{Name="DrivePath";Expression={$_.Caption}} |

                 ForEach-Object {Get-ChildItem -File -Path $_.DrivePath `

                  -Recurse -filter "$($Item)"})

          

                If ($Files -ne $Null)   

                    {

                        Write-Host "Deleteing: $($Files.Name)" -ForegroundColor Red

                        $Files | Remove-Item -Force

                    }

                    Else

                    {

              

                    }

            } # End Try Block

            Catch{}

        } # End: ForEach ($Item in $Pattern)

        Write-Host "Completed: $Client" `

         -ForegroundColor Gray `

         -BackgroundColor DarkGray

    }

<#

.SYNOPSIS

Removes files matching a pattern from removable storage devices

 

.DESCRIPTION

Discovers removable storage devices attached to remote clients

and then scans the files of that device for patterns in the file

name.  If the name matches, then the file is deleted.

 

.PARAMETER Pattern

A string pattern to search for.  Use of wildcard characters are accepted.

 

.PARAMETER ComputerName

A list of computer names to search for removable storage devices on.

 

.EXAMPLE

Remove-Contraband -ComputerName "Indy-CL1", "Indy-CL2" -Pattern "*ps123","PS456"

 

Scans both clients Indy-CL1 and Indy-CL2 for removable storage devices.

The cmdlet then scans those storage devices for any file ending in

"ps123" and any file named "PS456"  If found, these files are deleted.

 

#>

}

Monday, April 15, 2013

Use a hash table to create custom objects in PowerShell V3

As you continue to develop your skills in PowerShell, you will need to master the art of creating objects.  Objects are the result of your cmdlets efforts, packaged in a way that other cmdlets can use them.  A new feature to PowerShell V3 is the ability to create an object from a hash table.  This method may help with reducing the amount of typing required.

1

2

3

4

$Obj = [PSCustomObject]@{'Prop1'="hello";

'prop2'='World';

'Prop3'=[double]5;

"Prop4" = $True}

 

Line 1 creates the variable $Obj that will store our object.  We set it equal to a hash table of type PSCustomeObject. The PSCustomeObject class is designed for this purpose.  We also add our first property called Prop1 with a value of hello.  The semicolon is used to separate properties.  We could have continued to type the remaining lines on line 1, but the use of the semicolon allows us to break up this single line into multiple lines for better readability.

Line 2 adds a second property called prop2 with a value of World.  PowerShell will automatically select the data type for both of these properties to be of type string when either single or double quotes are used to encapsulate the value.

Line 3 demonstrates how to cast a data type in the hash table.  Normally PowerShell would cast the number 5 as an integer.  In this case we are casting this property to be of type Double.

Line 4 also demonstrates type casting, but in this case as a Boolean value.

Here is our output:

PS C:\powershell> $Obj

 

Prop1 prop2 Prop3 Prop4

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

hello World     5  True

 

And here is the member information of the object.

$Obj | GM

 

   TypeName: System.Management.Automation.PSCustomObject

 

Name        MemberType   Definition                   

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

Equals      Method       bool Equals(System.Object obj)

GetHashCode Method       int GetHashCode()            

GetType     Method       type GetType()               

ToString    Method       string ToString()            

Prop1       NoteProperty System.String Prop1=hello    

prop2       NoteProperty System.String prop2=World    

Prop3       NoteProperty System.Double Prop3=5        

Prop4       NoteProperty System.Boolean Prop4=True

Wednesday, April 10, 2013

Use PowerShell to list all server roles and the services that they are using

This was a good question that came up in my Windows Server 2008 Fundamentals course.  The student needed to list all of the server roles on the local server and the services that each role utilizes for a collage class she was taking.  This was actually an easy one to resolve.

Import-Module ServerManager

Get-WindowsFeature -ErrorAction Stop |

 Where-Object {($_.installed -eq $true) -and ($_.SystemService -ne $Null)} |

 Select-Object -Property Name, SystemService

 

This code requires the ServerManager module.  Since it was being executed on the local Windows 2008 R2 server, there was not an issue.  What about executing this code against remote clients? At this point, the code is only somewhat reusable.  One of my students worked in an environment of over 3000 servers. How could it be usable for him? The help file for Get-WindowsFeature does not show any built in remoting technology.  For this reason, we need to enable PowerShell Remoting.

 

PowerShell remoting is turned on by default on Server 2012 and Windows 8.  From Server 20008 R2 and Windows 7, follow these instructions to turn on PowerShell remoting in your domain using Group Policy. Below is the code to all this information to be recovered for remote clients.

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

 

Function Get-RoleServiceUsage

{

[cmdletbinding()]

Param(

    [Parameter(Mandatory=$True,

               ValueFromPipeline=$True,

               Position=0)]

               $Name = "LocalHost"

)              

    Begin {}

   

    Process

    {

        ForEach ($Item in (Invoke-Command -ComputerName $Name -ErrorAction Continue `

            -ScriptBlock {

                Param ($Name)

                Try

                {

                    Import-Module ServerManager -ErrorAction Stop;

                    Get-WindowsFeature -ErrorAction Stop |

                    Where-Object {($_.installed -eq $true) -and ($_.SystemService -ne $Null)} |

                    Select-Object -Property Name, SystemService

                }

                Catch

                {

                    Write-Host "Error: No ServerManager on Server: " `

                    -NoNewline -ForegroundColor Red -BackgroundColor DarkRed

                    Write-HOst "$Name"

                       

                }

            } -args $Name ))

       

       

        {

            Write-Output $Item

        }

    }

   

    End {}

 

<#

.SYNOPSIS

Returns the services being used by server roles.

 

.DESCRIPTION

Returns an object representing each role installed on the server and the services

that are being used being used by each role.

 

.PARAMETER Name

The Name of the server to recover role and service information from.

 

.EXAMPLE

"PHX-DC1" | Get-RoleServiceUsage

 

Name               : ADDS-Domain-Controller

SystemService      : {ntds*, netlogon*, kdc*, ntfrs...}

PSComputerName     : PHX-dc1

RunspaceId         : cd61ea87-1899-484b-887f-29180f7134de

PSShowComputerName : True

 

Name               : DNS

SystemService      : {dns*}

PSComputerName     : PHX-dc1

RunspaceId         : cd61ea87-1899-484b-887f-29180f7134de

PSShowComputerName : True

 

Returns the roles and their respective services from a single client.

 

.EXAMPLE

PHX-DC1" | Get-RoleServiceUsage |

    ForEach -process {Write-Host $_.Name -BackgroundColor Gray;

     $_ |Select-Object -ExpandProperty SystemService}

    

Returns a list of both the roles and ther services, with the roles

highlighted.

 

.NOTES

Requires the ServerManager module on each client this cmdlet is

executed against.

 

#>

} # End Function: Get-RoleServiceUsage

 

Line 1 is the declaration of our function, and the name of the cmdlet that we are creating: Get-RoleServiceUsage.

Lines 2 and 82 encapsulate the code of the function.

Line 3 enables this function to become a cmdlet by allowing the usage of the PowerShell Default Parameters.  To read more about the CmdletBinding attribute, take a look at the PowerShell help file About_Functions_Advanced_Parameters.

Line 4 starts our parameter block that ends at line 9

Lines 5 – 8 declares our only parameter, $Name.  This will be the name of a server that we want to retrieve information from.  Notice that the parameter has a default value of “LocalHost” and can accept input via the PowerShell pipeline.  This means we can pipe a comma seperated list of server names into this cmdlet so we can reach out to many servers easily.

Line 10 holds an empty BEGIN block.  This block is not used in this code.

Lines 12 – 37 holds our PROCESS block.  The Process block will execute once for each name piped to our cmdlet.

Line 14 starts a very complex ForEach statement.  Essentially the collection of objects that we are recovering from the servers are gathered starting with (Invoke-Command in line 14 and ends on line 31.  The results are stored in $Item for later processing.  The Invoke-Command cmdlet is used because we can send code to other clients using the –ComputerName parameter.

Line 15 starts the –ScriptBlock portion of the Invoke-Command cmdlet.  Everything inside of the curly braces from line 15 to line 31 is sent to the remote client.

Line 16 allows for a parameter to be sent the the remote client.  This parameter is called $Name and the actual value is sent from the –Args parameter on line 31.

Line 17 sets up some error handling.  We are looking for a potential error on Lines 19 or 20.

Line 19 will load the ServerManager module on the remote client.  If this fails, the Catch block on line 24 will execute.

Lines 20-22 is one continuous PowerShell command.  The first cmdlet is Get-WindowsFeature.  This cmdlet came from the ServerManager module and it will return a list of objects representing all the roles and features that are available to the remote server.

Line 21 filters the list of objects se we only will be working with objects that are both installed, and use a service as part of their functionality.

Line 22 filters out extra properties and returns to us an object containing the role’s name and the list of services that particular role uses.  This is the information that is stored in the variable $Item.

Lines 24 – 30 will handle any errors that occur on lines 19 and 20.  This block will execute should you accidental include clients in the search which do not have access to the ServerManage module.  Should RSAT be installed, you will get results.  This is another avenue for you to look into for additional error handling.

Lines 34-36 execute for each object recovered in the variable $Item from line 14.  In this case, the object is simply placed in the PowerShell pipeline.

Line 39 is the END block of our function.  It is not used.

Lines 42 – 82 is the help file for this function.

Line 83 ends the function.

 

Once you load this function into memory, you can access the help file by executing:

Get-Help Get-RoleServiceUsage –Detailed

Take a look at the examples to learn how to use it.