Thursday, 29 August 2013

Centrally Stored Modules - Pt. 3 - Preparing the Central Store


If you have followed my Previous posts on this topic, by now you would have learned a few basics:

- What a Script Module is
- How to create one
- How modules work in powershell
- Differences between powershell v2 and v3
Directory Structure

Before we begin with creation of the Central Repository, we need to think about a standardized way to name any modules which we create.  I like to name the files and folders in the following format:

(CSC = Compay Short Code)
CSC.Service

So here's a real world example from our own Production central Repository.

Each directory has the same name psm1 file located inside it and the functions contained within the psm1 files are related to the service in the directory name. (explained in Part 2)
Files Inside the Directory (Sharepoint)

This keeps it quite clear as to what each module's purpose is.

In addition to naming each folder this way, we need to standardize the way we name our functions.

I like to name the functions in the following format:

Verb-CSCFunctionName (where Verb is the approved Verb in the list by running the Get-Verb cmdlet)

Here's an Example of the naming convention for the Functions.
Get-Module -Listavailable in PowerShell v3

As you can see in the screenshot, all of the Exported commands follow the same naming convention.

Ok, now that we've decided on all the naming conventions, its time to create our Central repository.

(For these steps, substituse contoso.com with your own domain details)

  • Choose a server which you know is stable
  • Create a DNS CNAME for this server - (powershell.*domain FQDN*)
    • eg. powershell.contoso.com
    • I know some will question the use of this CNAME, but i like it as it makes it alot easier to remember the module path when you're accessing it from multiple locations
  • Create the following Folder structure (E:\Powershell\Modules\*ModuleDirectories*\psm1)
  • Share the Modules Folder
    • Everyone - Read Permissions
    • Ensure that you can access the module folder remotely by typing "\\powershell.contoso.com\Modules"

The following steps need to be done on any machine which you'd like to access your Modules from:
  • Edit the PSModulePath environment variable and add your Modules UNC Path (\\powershell.contoso.com\Modules)
    • You can do this in Windows by going to System Properties > Advanced System Settings > Environment Variables > Find the PSModulePath and add the UNC Path to the end of it
    • Or we can use Powershell to do this.
      • To add a temporary value that is available only for the current session:
        • $env:PSModulePath = $env:PSModulePath + ";\\Powershell.contoso.com:\Modules"
      • To add a persistent value that is available whenever a session is opened, add the following command to your PowerShell profile: 
        • $env:PSModulePath = $env:PSModulePath + ";\\Powershell.contoso.com:\Modules"
      • To add a persistent variable to the registry:
        • $oldPath=(Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PSModulePath).PSModulePath
        • $newPath=$oldPath+’;\\Powershell.contoso.com\Modules\’
        • Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PSModulePath –Value $newPath
Now you are ready to start creating functions in your Modules and start using them remotely.

Happy Moduling!






Friday, 26 July 2013

Centrally Stored Modules - Pt. 2 -Module Basics - Directories, Files, Functions and Module Manifest

Continuing on from the Module Basics explained in my Previous Post.

Lets look at some examples on the theory mentioned in the post.

We'll go ahead and create a new module called "MyModule" (we'll use the default folder paths for now)

1. Create a new folder called "MyModule" in one of the directories exposed to $env:PSModulePath
New-Item -Type Directory -Path "$Home\Documents\WindowsPowerShell\Modules\MyModule"

2. Inside the folder create a file called "MyModule.psm1"
New-Item -Type File -Path "$Home\Documents\WindowsPowerShell\Modules\MyModule\MyModule.psm1"

  • IMPORTANT: The Directory name created in Step 1 and the File Name in step 2 Must Match in order for the Get-Module -ListAvailable commandlet to work!

3.Now lets create a Module Manifest (which is basically a hash table of information which gets loaded into your powershell scope at the time of running Import-Module).
New-ModuleManifest -Path "$Home\Documents\WindowsPowerShell\Modules\MyModule\MyModule.psd1"

  • in Powershell 2.0 - Just running the above command will prompt for a bunch of Parameters to be entered - Enter as much or as little as you like.  What you enter here will be stored in the psd1 file.
  • in Powershell 3.0 - Just running the above command simply creates the psd1 file which you need to manually edit later.
  • IMPORTANT: When filling in the Module Manifest, for the Import-Module command to work, you MUST enter the top entry of the Hash Table.
    • In PS v2 - this entry is called "ModuleToProcess"
    • In PS v3 - this entry is called "RootModule"
  • Make sure to uncomment any other values which you intend to fill out.
4. Now that we have the files Created, lets create some basic functions inside the module.  To ensure that i differentiate the functions which i write, to the functions which are powershell native, i am going to prefix the names with "My".  At this stage i'll leave these functions empty.
Function Get-MyProcess {
 }
 Function Get-MyService {
5. So at this stage, we've created a module with 2 empty functions inside a module.  Now we need to expose these functions so that Powershell knows which commands to load into the Scope at the time of doing Import-Module.
There are 2 ways to do this:


  • Using the Export-ModuleMember cmdlet
    • To use this method, at the bottom of your MyModule.psm1 file, simply add
Export-ModuleMember -function Get-MyService 
Export-ModuleMember -function Get-MyService 
  • Using the Module Manifest
    • To use this method, open your MyModule.psd1 file, find the entry which reads "FunctionsToExport" and make it look like this:
    FunctionsToExport = @("Get-MyProcess",
        "
    Get-MyService")
      • Which method you chose is up to you, i prefer using the manifest as all the exposed information is kept within one file and is quite clear to read. 
      6. Now we are ready to test importing our new module.
      IMPORTANT: There is a distinct difference between powershell V2 and V3 in terms of how they handle importing modules.
      • In PS V2 - you must use Get-Module -ListAvailable to find your module.  Once you have confirmed it is on the List you can then run:
      Import-Module MyModule 
      • in PS V3 - you dont have to, it already scans inside each module folder inside $env:PSModulePath and it knows about MyModule already.  Simply start typing in Get-MyProcess or Get-MyService and it will find it.
      There you have it.  You now have your own module which can be listed as available and imported into your powershell session.



      Thursday, 20 June 2013

      Centrally Stored Modules - Pt. 1 - Module Basics

      As i do not come from a developer background, creating power shell modules always seemed like an impossible task.
      Every now and then i'd come across scripts which had weird sorts of comments at the top and these strange "Param" and [CmdletBinding()] script blocks which i could never understand.

      After all, at that stage my scripts were as simple as initializing a bunch of variables with hard coded values and pass them to New-ADUser command.

      Fast forward a couple of years, i'm starting to look for ways to no longer write static scripts and am now looking at ways to package my scripts into something more meaningful.

      Say hello to Power Shell Modules. Script Modules in particular.

      When i started looking at Power Shell Modules, immediately i thought about having a central place to store them and somehow to set it up so that admins can access these modules with ease.

      So what is a Script Module?

      A script module is basically a normal .ps1 script which has been renamed to .psm1.

      The difference between these 2 files is what you'd normally expect to see inside them.  
      While a .ps1 script will be a collection of functions and manipulated code to achieve a specific purpose (for example a script to email an html report), a .psm1 file will generally contain only functions.
      There is also a .psd1 file (Module Manifest file) which accompanies the .psm1 file. 

      So how do i create one?

      Lets say we want to make a module called MyModule.

      First thing we would create a folder called MyModule - Folder name is important as this is what Power Shell will read as the name of your Module.

      Inside that folder we would create MyModule.psm1 - This is the actual module script file which you will use to store your functions.
      Inside the same folder we would create a module Manifest.  Easiest way to do this is to run the New-ModuleManifest commandlet.  Specify the Path as ~path~\MyModule\MyModule.psd1, Fill in as many details as you like. 

       

      How does it all work in Power Shell?

      There is an environment variable called "PSModulePath".  By default there are 2 locations listed in this variable (C:\Users\*User*\Documents\WindowsPowerShell\Modules and C:\Windows\system32\WindowsPowerShell\v1.0\Modules\).
      When you start powershell, powershell checks those folders for a list of modules.  You can then run Get-Module -ListAvailable which will bring up a list of modules which you can import.

      to be continued...