Showing posts with label powershell. Show all posts
Showing posts with label powershell. Show all posts

Tuesday, December 31, 2019

Thank you Sitecore Community 2019

Amazing how fast 2019 has come and gone. So many hours spent working on and talking about Sitecore. In this post I share my appreciate for those donating through GitHub Sponsors.

GitHub Sponsors


It was a huge surprise to me this year when GitHub accepted my request (due to nominations) for the Beta program of GitHub Sponsors. If you've not heard about it you can read more about it here.


I was so excited the signup started for the beta program. Then much to my surprise the Sitecore community rallied behind me and helped nominate me. I'm confident this increased my chances of getting into the program. Now GitHub Sponsors is out of beta so you too can apply.

Shortly after the sponsors started to sign up one by one. I'm forever grateful for your contributions. In 2019 these beautiful people found me worthy of supporting.


Then I was like


via GIPHY

So you might be asking yourself, "Why support Michael West?". I'm a contributor to the module Sitecore PowerShell Extensions and this requires quite a bit of personal time. I've enjoyed working on it these past several years and your support helps keep me going. If you feel like now is the time you would like to join in then by all means click this link right here!

How have the donations been spent?

  • Purchased beer and root beer at various establishments.
  • Loaded up on 100% Maple Syrup. Don't judge.
  • Renewed SnagIt and Camtasia for the 2019 maintenance year.
  • Covered some expenses for the Sitecore Symposium 2019 trip.
  • Ordered new SPE gifts (stickers, coasters, buttons, etc.). If you are a sponsor and for some reason I haven't given you any of this please let me know. I'll ship it to you right away.
Photo of Michael and Adam
Photo of Michael and Adam at Symposium
Thank you so much to all those who donated through GitHub Sponsors.

Thursday, December 27, 2018

Sitecore Security for SXA Projects

Every new website requires some level of security configuration before launch. In this article we see one possible solution to applying security to sites built with the Sitecore Experience Accelerator (SXA).

Please note that the following scripts were written before the SXA module included scripts to manage security. I encourage you to evaluate those included out-of-the-box.

Role Configuration

Let's have a look at how the security will be setup for each tenant.


  • Each tenant will be organized by the company name. Companies have their own domain.
  • At least three of the six roles exist for all tenants (Admin, Editor, Developer). Each role inherits from a Base role (Sitecore Client Authoring, Sitecore Client Users) so they can login and manage content.
Tenant roles mapped to Sitecore roles
Running the script will present the user with a dialog like the following:

Dialog before security settings are applied
The dialog lists all of the available SXA tenants as well as any additional domains configured using the switching provider. This can be very helpful when using the Active Directory module because those users are not in the same domain as the tenant.

Show ribbon button using rules

Script Highlights


Let's walkthrough what changes are applied by the script.

Results output after completion
  • Site - Admin role granted access to help cleanup after users.
  • Home - Base role granted access to manage content.
  • Overlay - Admin role allowed to manage overlay content.
  • Data - Base role granted access to manage grandchildren. Prevents users from deleting global folders.
  • Media - Base role granted access to manage available media library folders.
  • Media Library - Base role granted access to manage media for this site.
  • Presentation - Developer role granted access to manage Rendering Variants, Partial Designs, etc.
  • Theme - Developer role granted access to manage media for this theme.
  • Data Templates - Developer role granted access to manage data templates.
  • Publishing Targets - Editor role granted access to publish to any target.
  • Languages - Everyone role granted access to read/write to all languages. This includes the tenant domain and additional domains selected.
  • System Settings - Developer role granted access to manage Modules, Settings, Tasks, and Workflows.
This will of course not cover the granularity that your company requires, but should provide you with a framework for crafting a tool for your own needs.

Hope this inspires you to build something great and share with the community.

The Scripts


Monday, August 27, 2018

Little Book of Sitecore PowerShell Tips


My friend Neil Shack released an excellent series of books that every Sitecore enthusiast should have entitled The Little Book of Sitecore Tips. I am honored to be a technical reviewer in the second edition and very much appreciate him giving me the opportunity. In this post I share details about how I would like to release a sister series called The Little Book of Sitecore PowerShell Tips.

The Vision


The Sitecore PowerShell Extensions module is an amazing add-on available for Sitecore. Those using it would agree that it provides incredible flexibility and opportunity for feature development. Even the documentation is amazing. The user base for SPE stretches around the globe, with each individual bringing a unique perspective.

Since the module is built by the community, I would like to give the community an opportunity to help build a book of their best tips and tricks.

The Mission


Before a book can be published there needs to be content. While I may have some experience with SPE, I don't have all the best ideas about what tips and tricks mean the most to new and seasoned users of the module. I'm requesting that anyone that has used the module submit their best tips.

I would like the best tips to be included in the book, with credit to the submitter on the same page as the tip. Just think, if you submit a great tip your name could be published in the book!

The Plan


Please follow this link to submit your ideas. Once I have enough I'll organize them by most creative and helpful. I appreciate your help. Let's built something awesome!




Here's a picture of Neil.

Neil Shack
Hi, this is Neil. Buy his books please. Thx.




Sunday, June 18, 2017

SPE Workflow Action using Slack Notifications

Have you ever wondered how to notify a user about workflow changes to an item in Sitecore, but not through email? In this post I'll show you in a few steps how to send notifications to a user or channel in Slack when transitioning an item's workflow state in Sitecore.

TL;DR;

  1. Setup a Slack authentication token here. The documentation indicates there are some newer ways to acquire a token, but for now we'll go with the low effort approach.
  2. Setup the PSSlack module for PowerShell found here. Optionally, run Install-Module PSSlack from an elevated PowerShell console. Big thanks to @pscookiemonster for putting this together.
  3. Create a SPE workflow action like described here.
  4. Update the script to send messages to Slack.
  5. Celebrate!

Example Notification



Monday, July 13, 2015

Sitecore PowerShell Extensions Remoting v2

Let me start off by saying that the work done by Himadri here is a great example at the flexibility of SPE. Not long ago Adam posted about Remoting in SPE, it became clear that we needed to have a Windows PowerShell module that users can setup outside of Sitecore that would come with all the necessary commands to interact with SPE. In our 3.1 release we included the module, so feel free to grab that now.

In this post I would like to show some recent enhancements made in 3.2 that will make interacting with SPE even better!

The packaged Windows PowerShell module can be found on the marketplace listed as SPE Remoting. That is the preferred method for interacting with SPE outside of the Sitecore environment. If you wish to use the same code from within the browser, such as to interact with another instance of SPE, you'll find the commands under here:
master:/system/Modules/PowerShell/Script Library/Platform/Functions/Remoting2

We've included all of the documentation below in our book.
When you execute the script or import the module you'll get the following commands:
  • New-ScriptSession - This can be reused between calls to all the other commands.
  • Invoke-RemoteScript - Best option for performing any remote script execution.
  • Send-MediaItem - Remotely upload.
  • Receive-MediaItem - Remotely download.
Let's walk through a few examples at using the commands.

Create a new session object that will contain a reference to the SPE session id and the web service proxy. Next we invoke a scriptblock on the server within the session.

If you would like to download images from the media library you can do something as simple as the following:

If you would like to upload images from the filesystem to the media library you can do something like this:

Saturday, May 16, 2015

Sitecore PowerShell Extensions - System Maintenance

Here recently I was thinking about how I could perform some of the system maintenance tasks that you would have to manually run from the Sitecore Control Panel. I decided to add these scripts to the System Maintenance script module in the Sitecore PowerShell Extensions module. I hope this encourages you to spend a little more time in SPE.

// michael

Friday, April 10, 2015

Sitecore PowerShell Extensions Tip - Count Items

Today I needed a quick report to find out the number of "pages" on our site. I came up with a quick estimate using the Sitecore PowerShell Extensions module.

I hope this encourages you to spend a little more time in SPE.

// michael

Thursday, February 26, 2015

Move Workstation To New OU With PowerShell

Question came up at work today on how to move a workstation in Active Directory from one OU to another. Here's what I came up with.

I hope this helps someone!

Import-Module ActiveDirectory

$computers = "PC1","PC2" # Optionally use Get-Content -Path C:\computers.txt
$computers | ForEach-Object { 
        $computer = "$($_)$"; Get-ADComputer -Filter { SamAccountName -eq $computer } | 
        Move-ADObject -TargetPath "OU=Retired Workstations,OU=Company,DC=company,DC=corp"
    }

// michael

Saturday, November 1, 2014

Sitecore PowerShell Extended with Gutters

Recently I challenged myself to find integrations with Sitecore PowerShell Extensions that have not yet been published. I saw this cool  article by ParTechIT and knew it was something I had to try. Of course I have to tell someone when I get it figured out.


After having already extended with pipelines I didn't expect this to take very long. Hopefully those reading this will learn something, decide to share it, and point out areas of improvement. Feel free to comment or make suggestions. I expect to add this to a future release of Sitecore PowerShell Extensions (SPE).

User Story:
As a spe user, I can create scripts to run when rendering gutters so that I don't have to compile the GutterRenderer.
As a spe user, the script can be configured just like any other GutterRender, so that I don't have to further complicate the setup.

Acceptance Criteria:

  • The gutter rendering scripts must reside under the following path:
    • /sitecore/system/Modules/PowerShell/Script Library/Content Editor/Gutters
  • The GutterRenderer must be configured under the following path:
    • /sitecore/content/Applications/Content Editor/Gutters
  • The example GutterRenderer must be stolen.
Some concepts you will see in this article:
  • Creating a GutterRenderer using Windows PowerShell code in SPE.
  • Configuring a GutterRenderer in Sitecore
First we begin with creating a new class in our Sitecore.SharedSource.PowerShell library. The class to create in this example is called GutterStatusRenderer.
using System;
using Cognifide.PowerShell.PowerShellIntegrations.Host;
using Cognifide.PowerShell.PowerShellIntegrations.Settings;
using Sitecore.Configuration;
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Shell.Applications.ContentEditor.Gutters;

namespace Sitecore.SharedSource.Gutters
{
    // Inherit from the GutterRenderer in order to override the GetIconDescriptor.
    public class GutterStatusRenderer : GutterRenderer
    {
        // We override the GetIconDescriptor so a script can be called in it's place.
        protected override GutterIconDescriptor GetIconDescriptor(Item item)
        {
            // The scriptId parameter is configured when we create a new gutter
            // here /sitecore/content/Applications/Content Editor/Gutters
            if (!Parameters.ContainsKey("scriptId")) return null;

            var scriptId = new ID(Parameters["scriptId"]);

            var db = Factory.GetDatabase("master");
            var scriptItem = db.GetItem(scriptId);

            // If a script is configured but does not exist then return.
            if (scriptItem == null) return null;

            // Create a new session for running the script.
            using (var session = new ScriptSession(ApplicationNames.Default))
            {
                var script = (scriptItem.Fields[ScriptItemFieldNames.Script] != null)
                    ? scriptItem.Fields[ScriptItemFieldNames.Script].Value
                    : String.Empty;

                // We will need the item variable in the script.
                session.SetVariable("item", item);

                try
                {
                    // Any objects written to the pipeline in the script will be returned.
                    var output = session.ExecuteScriptPart(script, false);
                    foreach (var result in output)
                    {
                        if (result.GetType() == typeof (GutterIconDescriptor))
                        {
                            return (GutterIconDescriptor) result;
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.Error(ex.Message, this);
                }
            }

            return null;
        }
    }
}

Second we need to create a new Gutter library and a Publication Status script. We'll come back to the content of the script later.

Third we need to create a new Gutter in the "core" database.


If you recall from the source code above, the scriptId indicates which script to call for this GutterRenderer. This will allow you to use the same GutterStatusRenderer class for all your gutter needs.

Finally we need to write our script. You'll notice that it's almost exactly what was stolen from ParTechIT, in PowerShell form.

<#
    Adapted from:
    http://www.partechit.nl/en/blog/2013/03/display-item-publication-status-in-the-sitecore-gutter
#>

# The $item variable is populated in the GutterStatusRenderer class using session.SetVariable.
if(-not $item) {
    Write-Log "The item is null."
    return $null
}
$publishingTargetsFolderId = New-Object Sitecore.Data.ID "{D9E44555-02A6-407A-B4FC-96B9026CAADD}"
$targetDatabaseFieldId = New-Object Sitecore.Data.ID "{39ECFD90-55D2-49D8-B513-99D15573DE41}"

$existsInAll = $true
$existsInOne = $false

# Find the publishing targets item folder
$publishingTargetsFolder = [Sitecore.Context]::ContentDatabase.GetItem($publishingTargetsFolderId)
if ($publishingTargetsFolder -eq $null) {
    return $null
}

# Retrieve the publishing targets database names
# Check for item existance in publishing targets
foreach($publishingTargetDatabase in $publishingTargetsFolder.GetChildren()) {
    Write-Log "Checking the $($publishingTargetDatabase[$targetDatabaseFieldId]) for the existence of $($item.ID)"
    if([Sitecore.Data.Database]::GetDatabase($publishingTargetDatabase[$targetDatabaseFieldId]).GetItem($item.ID)) {
        $existsInOne = $true
    } else {
        $existsInAll = $false
    }
}

# Return descriptor with tooltip and icon
$tooltip = [Sitecore.Globalization.Translate]::Text("This item has not yet been published")
$icon = "People/16x16/flag_red.png"

if ($existsInAll) {
    $tooltip = [Sitecore.Globalization.Translate]::Text("This item has been published to all targets")
    $icon = "People/16x16/flag_green.png"
    Write-Log "Exists in all"
} elseif ($existsInOne) {
    $tooltip = [Sitecore.Globalization.Translate]::Text("This item has been published to at least one target")
    $icon = "People/16x16/flag_yellow.png"
    Write-Log "Exists in one"
}

$gutter = New-Object Sitecore.Shell.Applications.ContentEditor.Gutters.GutterIconDescriptor
$gutter.Icon = $icon
$gutter.Tooltip = $tooltip
$gutter.Click = [String]::Format("item:publish(id={0})", $item.ID)
$gutter

Here's the final result.


That's pretty much it. Happy coding!

References:

  • http://www.partechit.nl/en/blog/2013/03/display-item-publication-status-in-the-sitecore-gutter
  • http://michaellwest.blogspot.com/2014/10/sitecore-powershell-extended-with-pipelines.html
// Mikey

Saturday, October 25, 2014

Sitecore PowerShell Extensions Tip 2 - Set Random Wallpaper

As of late I've spent more time using Sitecore PowerShell Extensions.Today I decided to change the wallpaper with a random image from the media library.

# Get all the first level items in the images folder.
$items = Get-ChildItem -Path "master:\media library\images\"
# Select an item at random.
$item = $items[(Get-Random -Maximum ($items.length - 1))]
$url = [Sitecore.Resources.Media.MediaManager]::GetMediaUrl($item)

# Get the user in need of a refreshed wallpaper.
$user = Get-User -Identity "sitecore\admin" -Authenticated
$user.Profile.SetCustomProperty("Wallpaper", $url)
$user.Profile.Save();

I hope this encourages you to spend a little more time in SPE.

Wednesday, October 22, 2014

Sitecore PowerShell Extended with Pipelines



Every once in a while I have what I think is a cool idea. Then I have to tell someone.

Thank you Adam for the encouragement. This took me a few days to finally write it all down. Hopefully those reading this will learn something, decide to share it, and point out areas of improvement. Feel free to comment or make suggestions. I expect to add this to a future release of Sitecore PowerShell Extensions (SPE).

User Story:
As a spe user, I can create scripts to run during user logging in, successful login, and logout so that I can automate tasks that are tedious.

Acceptance Criteria:

  • The scripts must fit into one of the available pipelines provided by Sitecore.
    • loggingin
    • loggedin
    • logout
  • The example scripts used must be stolen.

Some concepts you will see in this article:

  • Config include files
  • Pipelines
  • Configuration Factory with hint attribute and raw: prefix
First we begin with creating a new library project in Visual Studio. When we are complete with the example, we'll have a project that looks like this:


Second we need to reference Sitecore.Kernel and Cognifide.PowerShell libraries. You'll find the Cognifide.PowerShell library in the bin directory after installing SPE.

Third we will create our new pipeline processor which will execute our PowerShell scripts. Below is the skeleton of the class.
using Sitecore.Pipelines;

namespace Sitecore.SharedSource.Pipelines
{
    public abstract class PipelineProcessor<TPipelineArgs> where TPipelineArgs : PipelineArgs
    {
        protected void Process(TPipelineArgs args)
        {
        }
    }
}

We can go ahead and create our three pipelines to extend the PipelineProcessor. Below is the complete implementation of each pipeline.


using Sitecore.Pipelines.LoggedIn;

namespace Sitecore.SharedSource.Pipelines.LoggedIn
{
    public class LoggedInScript : PipelineProcessor<LoggedInArgs> { }
}

using Sitecore.Pipelines.LoggingIn;

namespace Sitecore.SharedSource.Pipelines.LoggingIn
{
    public class LoggingInScript : PipelineProcessor<LoggingInArgs> { }
}

using Sitecore.Pipelines.Logout;

namespace Sitecore.SharedSource.Pipelines.Logout
{
    public class LogoutScript : PipelineProcessor<LogoutArgs> { }
}

Let's go ahead and setup our script libraries in Sitecore before we create the include config and finish out the implementation of running the scripts.


Now that we have the three pipeline libraries, we can create the include config to map to those. I prefer this solution so I don't have to hard code the GUID for each in compiled code.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <processors>
      <loggingin argsType="Sitecore.Pipelines.LoggingIn.LoggingInArgs">
        <!-- Pipeline to run scripts while the user is logging in. -->
        <processor patch:after="processor[position()=last()]" mode="on" type="Sitecore.Sharedsource.Pipelines.LoggingIn.LoggingInScript, Sitecore.SharedSource.PowerShell">
          <config hint="raw:Config">
            <!-- /sitecore/system/Modules/PowerShell/Script Library/Pipelines/LoggingIn -->
            <libraryId>{83C826B6-C478-43D9-92BD-E5589F50DA27}</libraryId>
          </config>
        </processor>
      </loggingin>      
      <loggedin argsType="Sitecore.Pipelines.LoggedIn.LoggedInArgs">
        <!-- Pipeline to run scripts after the user is logged in. -->
        <processor patch:after="processor[position()=last()]" mode="on" type="Sitecore.Sharedsource.Pipelines.LoggedIn.LoggedInScript, Sitecore.SharedSource.PowerShell">
          <config hint="raw:Config">
            <!-- /sitecore/system/Modules/PowerShell/Script Library/Pipelines/LoggedIn -->
            <libraryId>{D0226A69-F15D-4CBF-812C-BFE3F14936C5}</libraryId>
          </config>
        </processor>
      </loggedin>
      <logout argsType="Sitecore.Pipelines.Logout.LogoutArgs">
        <!-- Pipeline to run scripts when the user logs out. -->
        <processor  patch:after="*[@type='Sitecore.Pipelines.Logout.CheckModified, Sitecore.Kernel']" mode="on" type="Sitecore.Sharedsource.Pipelines.Logout.LogoutScript, Sitecore.SharedSource.PowerShell">
          <config hint="raw:Config">
            <!-- /sitecore/system/Modules/PowerShell/Script Library/Pipelines/Logout -->
            <libraryId>{EE098609-4CA4-4FEE-8A86-3AB410AB9C38}</libraryId>
          </config>
        </processor>
      </logout>
    </processors>
  </sitecore>
</configuration>

The pipeline is pretty standard. I did have to place the LogoutScript pipeline to be placed right after CheckModified, otherwise the username will be anonymous.

Notice the config section inside the processor. I found an example here by Partech which helped to setup the parameters in the config. John West has a nice article explaining the different options.

With that said, I'll show the remaining implementation of the PipelineProcessor. The code follows a few steps:

  1. Read the libraryId configured for the specified pipeline. A static collection would create a problem in this example, so be sure to leave it as it is below.
  2. If the library item contains any scripts, then continue.
  3. For each script defined in the pipeline library create a new session and execute the script. The args parameter is passed as a session variable for use in the scripts.


    public abstract class PipelineProcessor<TPipelineArgs> where TPipelineArgs : PipelineArgs
    {
        protected PipelineProcessor()
        {
            Configuration = new Dictionary<string, string>();
        }

        protected void Process(TPipelineArgs args)
        {
            Assert.ArgumentNotNull(args, "args");

            Assert.IsNotNullOrEmpty(Configuration["libraryId"], "The configuration setting 'libraryId' must exist.");

            var libraryId = new ID(Configuration["libraryId"]);

            var db = Factory.GetDatabase("master");
            var libraryItem = db.GetItem(libraryId);
            if (!libraryItem.HasChildren) return;

            foreach (var scriptItem in libraryItem.Children.ToList())
            {
                using (var session = new ScriptSession(ApplicationNames.Default))
                {
                    var script = (scriptItem.Fields[ScriptItemFieldNames.Script] != null)
                        ? scriptItem.Fields[ScriptItemFieldNames.Script].Value
                        : String.Empty;
                    session.SetVariable("args", args);

                    try
                    {
                        session.ExecuteScriptPart(script, false);
                    }
                    catch (Exception ex)
                    {
                        Log.Error(ex.Message, this);
                    }
                }
            }
        }

        protected Dictionary<string, string> Configuration { get; private set; }

        public void Config(XmlNode node)
        {
            Configuration.Add(node.Name, node.InnerText);
        }
    }

Finally, create your scripts in the libraries and watch it in action. Each of my example scripts are adapted from other articles and are linked at the end of this post.



That's pretty much it. If you really want to mess with your colleagues, write a script to send them a phony email every time they login and logout.

References:
  • http://www.sitecore.net/Learn/Blogs/Technical-Blogs/John-West-Sitecore-Blog/Posts/2011/02/The-Sitecore-ASPNET-CMS-Configuration-Factory.aspx
  • http://www.partechit.nl/en/blog/2014/09/configurable-pipeline-processors-and-event-handlers
  • http://www.matthewkenny.com/2014/10/custom-sitecore-pipelines/
  • Some scripts you can use. The random desktop background is really useful.
    • http://www.sitecore.net/Learn/Blogs/Technical-Blogs/John-West-Sitecore-Blog/Posts/2012/12/Automatically-Show-the-Quick-Info-Section-in-the-Content-Editor-of-the-Sitecore-ASPNET-CMS.aspx
    • http://www.sitecore.net/Learn/Blogs/Technical-Blogs/John-West-Sitecore-Blog/Posts/2010/07/Randomize-Sitecore-Desktop-Background-Image.aspx
    • http://sitecorejunkie.com/2013/06/08/enforce-password-expiration-in-the-sitecore-cms/
    • http://sitecorejunkie.com/2013/09/24/unlock-sitecore-users-items-during-logout/

Wednesday, October 8, 2014

Sitecore PowerShell Run Task On Demand

Recently I needed to help a colleague run a scheduled task on-demand. Immediately I thought to myself, Sitecore PowerShell Extensions can do it! I was certain other developers had created a solution, but I needed something quick.

helped by providing one out-of-the-box way to accomplish the task. The short answer is to use the Task Manager. Have a look under Sitecore -> PowerShell Toolbox -> Task Manager


You are then presented with a delightful screen which provides you with options like Execute Now and Edit Schedule.


 also had a good suggestion. Oh wait, that was me :)

This solution creates a context menu item that can be made visible when selecting an item with the Schedule template.


What we'll do here is create a new PowerShell Script item called Run Task, set a rule on it to only appear for the Schedule template, and write some simple code to run the task:

$item = Get-Item -Path .
if($item) {
  $schedule = Get-TaskSchedule -Item $item
  Start-TaskSchedule -Schedule $schedule
}





You can also confirm that the scheduled task completed successfully by checking the Log Viewer.

(coincidentally with the same last name) did provide a detailed article on an approach that does not the module.
also provided details to a module that provides an alternative experience to the schedule editor.

I hope this helps someone.

// Michael

Saturday, June 14, 2014

PowerShell Revisited - Running Commands

Running PowerShell Commands
The command Get-Verb is an example of a cmdlet (pronounced "command-let"). Cmdlets are structured verb-noun, where the noun is singular.
Below we will get a list of approved verbs in PowerShell, then format the results to fill the screen from left to right:
PS C:\> Get-Verb | Format-Wide -AutoSize
Add           Clear         Close         Copy         Enter        Exit         Find         Format       Get
Hide          Join          Lock          Move         New          Open         Optimize     Pop          Push
Redo          Remove        Rename        Reset        Resize       Search       Select       Set          Show
Skip          Split         Step          Switch       Undo         Unlock       Watch        Backup       Checkpoint
Compare       Compress      Convert       ConvertFrom  ConvertTo    Dismount     Edit         Expand       Export
Group         Import        Initialize    Limit        Merge        Mount        Out          Publish      Restore
Save          Sync          Unpublish     Update       Approve      Assert       Complete     Confirm      Deny
Disable       Enable        Install       Invoke       Register     Request      Restart      Resume       Start
Stop          Submit        Suspend       Uninstall    Unregister   Wait         Debug        Measure      Ping
Repair        Resolve       Test          Trace        Connect      Disconnect   Read         Receive      Send
Write         Block         Grant         Protect      Revoke       Unblock      Unprotect    Use

Microsoft has provided a nice page on the verb naming rules which can be found here.
The commands you use in cmd.exe can also be used within PowerShell since they are either aliased, new functions, or the external executable is called.
  • dir is an alias for Get-ChildItem
  • md is an alias for mkdir which is a function for New-Item
  • rmdir is an alias for Remove-Item
Some easy commands that just work:
  • Get-Process
  • Get-Service
  • Get-Date
  • Get-HotFix
  • Get-History
  • Start-Transcript, Stop-Transcript
  • Get-ChildItem
Now you may be wondering why the names seem so generic. The idea is that if the names are consistent then you can easily discover new commands. In addition, some commands can be reused in multiple areas such as managing the registry and filesystem. Here is a good example with Get-PSDrive:
PS C:\> Get-PSDrive

Name           Used (GB)     Free (GB) Provider      Root                                               CurrentLocation
----           ---------     --------- --------      ----                                               ---------------
Alias                                  Alias
C                  81.37        151.42 FileSystem    C:\
Cert                                   Certificate   \
E                                      FileSystem    E:\
Env                                    Environment
Function                               Function
HKCU                                   Registry      HKEY_CURRENT_USER
HKLM                                   Registry      HKEY_LOCAL_MACHINE
I                1112.16        305.87 FileSystem    \\chs-fs01_users\Users\Michael.West
Variable                               Variable
WSMan                                  WSMan
Y                   8.88          3.12 FileSystem    \\chs\data

PowerShell uses a variety of providers such as those for connecting to the file system and the registry. This design allows one to use for example, the Remove-Item command to delete a file or delete a registry key. Sweet!
PS C:\> $item = New-Object -TypeName PSObject -Property @{Name="Michael";Height=73;}
PS C:\> $item | Format-List


Height : 73
Name   : Michael

Here I created a new PSObject to contains some details about my name and height. Let's see the member information.
PS C:\> $item | Get-Member


   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()
Height      NoteProperty System.Int32 Height=73
Name        NoteProperty System.String Name=Michael

As you can see, the TypeName is "System.Management.Automation.PSCustomObject" and the new properties "Name" and "Height" are listed. The object type will be relevant to whatever object is piped in to Get-Member.

Get-PSDrive
Gets the Windows PowerShell drives in the current session.
Example:
# Displays details about the local disk C.
Get-PSDrive C
Random fact:
Try this: (Get-PSDrive)[0].Name <# Returns the name of the first object. #>
Try this: (Get-PSDrive)[0].GetType() <# Returns the type of the first object. #>
Set-Location
Sets the current working location to a specified location.
Example:
# Changes the location to the registry hive HKEY_LOCAL_MACHINE. The colon is required.
Set-Location HKLM:

PS C:\> Set-Location HKLM:
PS HKLM:\> Set-Location C:
PS C:\> Set-Location Alias:
PS Alias:\> dir | more

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Alias           % -> ForEach-Object
Alias           ? -> Where-Object
Alias           ac -> Add-Content
Alias           asnp -> Add-PSSnapin
Alias           cat -> Get-Content
Alias           cd -> Set-Location
Alias           chdir -> Set-Location
Alias           clc -> Clear-Content
Alias           clear -> Clear-Host
Alias           clhy -> Clear-History
Alias           cli -> Clear-Item
As you can see in the image above, I changed to the registry, then the C drive, then to Alias. In all of these locations, you can run the standard commands such as dir, ls, cd and so on. In the image you can also see that cd is an alias for Set-Location.
Below are some command aliases common in other environments.
CommandAliases
Copy-Itemcpi, cp, copy
ForEach-Objectforeach, %
Get-ChildItemdir, ls
Get-Commandgcm
Get-Contentgc, type, cat
Get-Helphelp
Get-Locationgl, pwd
Move-Itemmi, mv, move
Rename-Itemrni, ren
Set-Locationcd, chdir
Where-Objectwhere, ?
Remove-Itemri, rd, del, rm, rmdir
Random fact:
To count the number of items return, use Measure-Object. Use additional switch parameters such as -Sum and -Average.
Try this: Get-Process | Measure-Object <# Returns a table with the results of Measure-Object. #>
Try this: (Get-Process | Measure-Object).Count <# Returns the count value. #>
Get-Content
Gets the content of the item at the specified location.
Example:
# Reads the entire contents of the file.
Get-Content -Path C:\log.txt
Add-Content
Adds content to the specified items, such as adding words to a file.
Example:
# Appends the text to the file log.txt.
Add-Content -Path C:\log.txt -Value "The quick brown fox jumps over the lazy dog."
Out-File
Sends output to a file.
Example:
# The first command takes a snapshot of all the running processes. 
# The list passed through pipeline to Out-File which is then written to log.txt.
Get-Process | Out-File -FilePath C:\log.txt
Write-Host
Writes customized output to a host. The information is not kept in the pipeline.
Example:
# The text is written to the console window.
Write-Host "This text is written to the host, such as the console window."
Write-Output
Sends the specified objects to the next command in the pipeline. If the command is the last command in the pipeline, the objects are displayed in the console.
Example:
# The snapshot of running processes is saved into the variable p. The variable p is then written to the console window.
$p = Get-Process; Write-Output -InputObject $p
Write-Verbose
The text is written to the verbose message stream. This is commonly used in PowerShell scripts.
Example:
# The text is written to the verbose stream. If the switch -Verbose is used, the text will be written to the console window.
Write-Verbose -Message "The quick brown fox jumps over the lazy dog."

New-Item
Creates a new item. The item can be a new registry key, file, directory, etc. The type of item created depends on which provider you are connected to.
Example:
# A new file is created with the specified text.
New-Item -Path C:\ -Name log.txt -ItemType "file"
New-Item -Path C:\log.txt -ItemType "file" -Value "The quick brown fox jumps over the lazy dog."

Monday, June 2, 2014

Sitecore PowerShell Extensions Manual

This document is a work in progress. Hopefully as you continue to refer to this you'll see the updates.


Saturday, May 3, 2014

Archive Log Files with Sitecore PowerShell Extensions

The other day I was talking to Mike Reynolds (@mike_i_reynolds) about his idea of a FileWatcher for the Sitecore CMS log files. That sounded like a great opportunity to use the Sitecore PowerShell Extensions module found on the Sitecore Marketplace.

The process can be broken down into these few steps:

  1. A scheduled task to run a script
  2. The script zips up the log files and saves to an archive folder
Below are the scripts to get the job done.

I added the Compress-Archive script here: /sitecore/system/Modules/PowerShell/Script Library/Functions/Compress-Archive
I then added the Archive Logs script here: /sitecore/system/Modules/PowerShell/Script Library/Tasks/Archive Logs

Finally, I created the scheduled task using the PowerShellScriptCommand.
You'll notice here that I'm using a custom field for the Task Scheduler so it's easier to see what's configured.

These scripts should be included in a future build of Sitecore PowerShell Extensions but feel free to start using now!

Sunday, April 6, 2014

Reports with Sitecore PowerShell Extensions

I was trolling through the Sitecore Marketplace the other day and found this cool module for reporting about media library items called Unused Media Manager. I thought this would be a great example of how you can adapt code that would traditionally be written in C# and turn it into a simple script in Powershell.

Here's a quick example of where the new scripts appear within the Sitecore tree.

As you can see, SPE provides a reports folder where you can add scripts that will appear under Reporting Tools > PowerShell Reports.

I selected the Unused media items script which produced the following results:
The above window is produced by using the "Show-ListView" command.

Friday, January 17, 2014

Report Duplicate AD Users By EmployeeID

Note: The employeeID is formatted to 7 characters so that if you had numbers with leading 0s they would still be matched.

Saturday, September 7, 2013

Sitecore PowerShell Extensions Mixing C# and PowerShell



$code = @"
using System;

namespace AwesomeNamespace {
    public enum AwesomeActivityType {
        Nothing,
        Sleeping,
        Eating,
        UsingSPE
    }
    public class AwesomeClass {
        public string DoSomethingAwesome(AwesomeActivityType activity) {
            return String.Format("Your awesome activity is {0}. That's awesome!", activity);
        }
        
        public static string DoSomethingAwesomeAnytime(){
            return "There, their, the're";
        }
    }
}
"@
Add-Type $code

$awesome = New-Object AwesomeNamespace.AwesomeClass
$awesome.DoSomethingAwesome([AwesomeNamespace.AwesomeActivityType]::UsingSPE)
[AwesomeNamespace.AwesomeClass]::DoSomethingAwesomeAnytime()