Feeds:
Posts
Comments

Posts Tagged ‘PowerShell’

So I needed to automate some configuration tasks on a Cisco ASA firewall, and thought it will be an easy task since it has an SSH interface. But after a couple of failed tries and some searching on the web, I realized that I could not use the standard SSH command mode to access the ASA and that the only working and reliable solution out there (that I found) was on this post: “How to automate scripted commands to a Cisco ASA via ssh“. However,  it relies on the “Expect” Linux command, and in my case, I preferred to execute the script directly from the System Center Orchestrator machine, which is windows based. Some blogs mentioned the windows Plink.exe command as an option too, this solution worked but it did not allow to do validations and extra logic during the script execution, as the script is sent to the device in one block. I also found this PowerShell module “SSH from PowerShell using the SSH.NET library”  that sounded promising at first, but  works with the standard SSH command and when trying to use it, I was not able to connect to my ASA firewall.
Finally, I decided to develop my own PowerShell module base on the SSH.Net library, but unlike the above module, I will be using only the SSH shell stream to interact with the device. The tricky part of working with shell stream is that there is no notification when a command execution is completed. One way to overcome this is by checking for available data on the output stream. Most of the commands’ script are easy to handle because it is valid to assume that the command execution is completed as soon as there is something in the output stream. The problem is that this assumption is not true for long-running commands that report their progress during the execution. To support this kind of commands I needed to add support for specifying a timeout before assuming the command was completed and also allow to specify a regular expression to ignore progress messages when waiting for the command output. The module also handle cleaning extra BS(\u0008) characters from the output stream. That noise characters usually appeared when executing a long command.
Proof of concept – script to create a new network object:

Import-Module SshShell

$elevatedPrompt = "#.$"
$configPrompt = "\(config\)#.$"
$objectPrompt = "object\)#.$"

$s = New-SshSession -SshHost $asaIP -User $user -Password $password
Send-SshCommand $s "enable" -Expect "Password:"
Send-SshCommand $s "$elevatedPassword" -Expect $elevatedPrompt

Send-SshCommand $s "show run object id $objectId" -Expect $elevatedPrompt

if ($s.LastResult -match "does not exist") {
	Send-SshCommand $s "conf t" -Expect $configPrompt
	Send-SshCommand $s "object network $objectId" -Expect $objectPrompt
	Send-SshCommand $s "description $description" -Expect $objectPrompt
	Send-SshCommand $s "host $hostIP" -Expect $objectPrompt
	Send-SshCommand $s "end" -Expect $elevatedPrompt
	Send-SshCommand $s "write mem" -Expect "[OK]" -WaitUnlimitedOn "configuration\.\.\.|Cryptochecksum|copied"
}

Close-SshSession $s

Notes:

  • These PowerShell variables are prepopulated with values and have self-explanatory names: $asaIP, $user, $password, $elevatedPassword, $objectId, $description, $hostIP.
  • The value of the “Expect” parameter is a regular expression. If the result of the command doesn’t match that expression an exception will be thrown.
  • To access the result of the Send-SshCommand cmdlet you can either use the cmdlet output or use one of the session variable properties: LastResult, LastResultLine or AllResult.

To deploy the module, just copy the SshShell folder to one of the PSModulePath values (for Orchestrator server copy it to “SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\Modules”) and make sure the dll files are not blocked. The module works with PowerShell 2.0 and require .net framework 3.5.

Download the module and the source

Read Full Post »

You can probably find several blog posts out there about remotely executing simple commands and scripts against Exchange servers, but trying to implement these examples on a “real” functional script, can introduce some annoying problems that nobody seems to mention. This was the case when I tried to develop a web page that was supposed to assist with managing a multi-tenant exchange 2010 SP2 environment. I got some startup scripts from Jacob Dixon’s blog and after some minor modifications I was able to execute them locally on the Exchange server without any problems, it was only when I tried to call these scripts from my web page that problems started:

  • Problem 1: Following a TechNet library post (http://technet.microsoft.com/en-us/library/dd335083), I tried, firstly, to open a remote PowerShell session from a C# application, to the Microsoft.Exchange configuration on a CAS server. I connected successfully but found that the execution context was very limited and restricted as it didn’t even allow assigning PowerShell variables (got an “Assignment statements are not allowed in restricted language mode or a Data section” exception), meaning you almost can’t do any scripting with it.
  • Problem 2: So I tried connecting to the default PowerShell  WSMAN (http://{ServerName}:5985/wsman) and executing the script, only to find that though I have full permissions, when trying to execute an exchange’s command, it asked to provide the server argument as it didn’t recognize it executing on an exchange server.  I didn’t want to change my scripts, so I didn’t continue with this approach.
  • Problem 3: So I tried to open a local PowerShell session and from this session I used the Import-Session commandlet to connect to the remote Microsfot.Exhange configuration.  I connected successfully and had full permissions with the right execution context. However,  while re-trying to execute the script I found that the commandlet New-Mailbox doesn’t exist.
    Quick solution:  Executed the “Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010” command and magically the command is available.
  • Problem 4:  Trying again to execute the script, I got a new error: “New-Mailbox : Load balancing failed to find a valid mailbox database.”. Ok – so I tried to specify the database explicitly with the –Database argument and got this error: “New-Mailbox : Couldn’t find database “{DB Name}”. Make sure you have typed it correctly. ”. I googled it and found some forums that suggested to make sure the database exists and is mounted, of course my mailbox database did exist and was mounted as the script worked from the local exchange server. So I tried a different approach;  opened a remote PowerShell session to the default PowerShell WSMAN and from that remote session I imported a new session to the Microsoft.Exchange configuration. This approach eliminated the error message and the mailbox was successfully created.
  • Problem 5:The PowerShell script also included some Active Directory commands, for creating a new AD account with the mailbox, which required loading the activedirectory module. When I tried to import the module I got this warning:
    • Error initializing default drive: ‘Unable to contact the server. This may be because this server does not exist, it is currently down, or it does not have the Active Directory Web Services running.‘.

    Not really a helpful message but googling it I understood that I got into a double hop problem, as the AD is installed on a different machine. So I decided to open the first remote session with the CredSSP authentication method (which enables double hops). This wasn’t a trivial task but luckily, Drew has an excellent blog post about this topic (http://werepoint.blogspot.ca/2012/03/setting-up-ps-remoting-for-all-that.html) that helped me to enable it.

  • Problem 6: After successfully creating a remote PowerShell session with the CredSSP authentication, I tried again to import the activedirectory module and got “Out of Memory” Exception.  To solve this one, I executed this command on the remote server:
winrm set winrm/config/winrs @{MaxMemoryPerShellMB="1024"}
  • Problem 7: Now my script was executing successfully but with all the parameters still hardcoded on the script, when I tried to make it more generic and pass the remote script parameter values from the C# application I found that I could not use the following code:
    powershell.Runspace.SessionStateProxy.SetVariable("{Param name}", "{Param value}");
    

    As the SessionStateProxy object doesn’t initialize with a remote PowerShell sessions. To overcome this, I changed my code to iterate the parameters and for each, add a “Set-Variable” Command with the relevant values like

foreach (var parameter in parameters)
{
   Command command = new Command("Set-Variable");
   command.Parameters.Add("Name", parameter.Key);
   command.Parameters.Add("Value", parameter.Value);
   this.powerShell.Commands.AddCommand(command);
}

this.powerShell.Invoke();

So, after a challenging day I ended up with a basic but complete demo for remotely running a script on Exchange 2010 SP2 server that creates a new Tenant’s mailbox. Hopefully this post will save you some time implementing similar tasks. I attached here the code for this demo web page.

Read Full Post »

Alex Crome had recently published a good article about Creating a factory default widgets plugin. After trying to follow his process to develop some widgets for our community site I found a couple of issues with the proposed method:

  • Many repeating tasks. For each widget you need to:
    • Copy&paste the xml provided on the article.
    • Generate new GUID and set it in the xml file.
    • Create new folder using said GUID as the name, under the widgets’ folder.

    Though all Telligent’s out-of-the-box widgets follow the same standards, implementing them, will require some additional steps:

    • Creating configuration elements for the widget title and for the widget configuration. Using these configurations in the widget xml file.
    • Adding a ui.js file to the widget and using the registerEndOfPageHtml method to include this file with the widget.
    • Defining a property with the namespace of the project in the ui.js file and extending the JQuery object.
    • Defining a register function in the ui.js file and calling this function from the widget xml file providing the context object.
  • After creating a few widgets in one project it becomes more difficult to work with these GUID folders; updating the widget requires you to open the widget xml, check the widget’s GUID and look for a matching folder.
  • Deploying any changes to the widget files requires opening a browser on the site control panel and from the developer tools clicking the “Clear Cache” button.

Personally, I feel this method requires a lot to do before you even begin developing your widget…

So, being my old lazy self I started thinking of a way to reduce all the manual work described so far while enforcing best practice and ended up with 2 visual studio item templates to do the work for me.

After deploying the item templates, the process of developing widget in visual studio will look like this:

  1. Open a new Class Library project.
  2. Right click on the project name and open the project properties. Under Application tab set the Assembly name and the default namespace.
  3. Save the solution.
  4. Add reference to Telligent.Evolution.Components.dll and Telligent.Evolution.ScriptedContentFragments.dll.
  5. Right click on the project name and select add > new item. Choose the  “WidgetFactoryDefaultProvider” from the installed templates.WidgetFactoryDefaultProvider
  6. Give the default provider a name like [CompanyName]FactoryDefaultProvider.cs
  7. When you click on the Add button the following window will open
    factory dialog
  8. On the Deployment site URL box, enter the URL for the site you would like to automatically deploy the widgets to (do not include any page name like default.aspx as suffix).
  9. On the Deployment site root folder box, enter the root folder of the above site (the folder that contains the bin folder).
  10. If you would like that every time you deploy an update the deployment script will automatically delete all the content of the widget provider folder, leave the checkbox unchecked. Otherwise, existing files will remain on the folder and only files that exist in the project will be overwrite.
  11. Click the create button. The item template will do the following tasks automatically:
    1. Create DefaultWidget folder under the project root.
    2. Create a factory default widgets plug-in with a new GUID as the provider identifier.
    3. Copy an assembly to the site bin folder that enable clearing the cache.
    4. Copy a generic handler file to the utility folder to access the above assembly.
    5. Create the file WidgetDeploy.ps1, a PowerShell script based on the answer you provided for deploying the files to the Telligent site and clear the cache.
  1. Compile the project and copy the result assembly to the Bin folder of the deployment site or just add the new class library as a reference to the deployment site project.
  2. Enable the new provider from the “Manage plugins” page.
  3. To simplify the execute of the PowerShell script you can add an external tool in visual studio:
    1. In the Tools menu, choose External Tools.
    2. In the External Tools dialog box, choose Add, and enter a name for the menu option in the Title box like “Update widget’s files”.
    3. In the Command box, enter powershell.exe
    4. In the Arguments box, enter "& '$(ProjectDir)WidgetDeploy.ps1'"
    5. Click on the OK button. After you have added a tool to the Tools menu, you can easily launch the update widget files tool from the tool menu.

To add new widgets to the project:

  1. Under the default widget folder add new item and choose the Widget template.
  1. In the name box, enter the name of the widget and click Add.
  2. This will do the following tasks automatically:
    1. Create folder with the widget name.
    2. Create under this folder the widget xml file and ui.js file.
    3. The xml file and the ui.js contain all the necessary content as described above (new GUID, default configuration, namespace registration …)

The development process should follow these steps:

  1. Add/Edit a widget definition or its supplementary files.
  2. From the Tool menu click the “update widget files”.
  3. Review the change in the Telligent Evolution site.
  4. Repeat.

To deploy the item templates:

  1. Download this file  and extract the RAR file.
  2. Execute “DeployTemplates.cmd”
  3. Make sure that PowerShell is in the right version and defined to allow executing unsigned scripts:
    1. Execute “StartPowerShell.cmd”
    2. Type Get-Host and make sure the version is 2.
    3. Type Get-ExecutionPolicy.
    4. If the response is Restricted type the following command:
      Set-ExecutionPolicy RemoteSigned

The item templates source is also included in the RAR file.

Read Full Post »