I wanted to create TDS packages using the version from the project assembly version.
Here's a piece of code that I finally figured out how to accomplish dynamically. Place at the bottom of your .scproj file.
Tuesday, November 26, 2013
Saturday, November 23, 2013
Friday, October 25, 2013
Sunday, September 22, 2013
Sitecore Integrated with Ace Code Editor
Check out my latest video showing you how to configure the EditHtml dialog with the Ace Code Editor!
Links:
(function($){ $('head').append("<style>div[id$=RibbonPanel],textarea[id$=Html] { display: none; } #CodeEditor { width: 100%; height: 100%; } </style>"); $(function() { var html = $('textarea[id$=Html]'); var ce = $("<div id='CodeEditor' />"); html.after(ce); var codeeditor = ace.edit(ce[0]); codeeditor.setTheme("ace/theme/monokai"); codeeditor.session.setMode("ace/mode/html"); codeeditor.setShowPrintMargin(false); codeeditor.session.setValue(html.val().trim()); codeeditor.session.on('change', function () { html.val(codeeditor.session.getValue()); }); ace.config.loadModule("ace/ext/emmet", function () { ace.require("ace/lib/net").loadScript("/Scripts/ace/emmet-core/emmet.js", function () { codeeditor.setOption("enableEmmet", true); }); codeeditor.setOptions({ enableSnippets: true, enableBasicAutocompletion: true }); }); ace.config.loadModule("ace/ext/language_tools", function (module) { codeeditor.setOptions({ enableSnippets: true, enableBasicAutocompletion: true }); }); }); }(jQuery));
Links:
- http://ace.c9.io
- https://github.com/ajaxorg/ace-builds/
- http://michaellwest.blogspot.com
Wednesday, September 11, 2013
Sitecore Generic Shortcodes
I really enjoyed reading Sitecore Junkie's post about using Shortcodes in Sitecore. Here's an example of one I built for generic item shortcodes.
using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using Sitecore; using Sitecore.Data; namespace Concentra.Web.Configuration.Pipelines.ExpandShortcodes { /// <summary> /// Expands shortcodes with the following format: /// [item id=110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9 fieldname="Title"] /// </summary> public class ExpandItemShortcodes : ExpandShortcodesProcessor { public override IEnumerable<Shortcode> GetShortcodes(string content) { if (String.IsNullOrWhiteSpace(content)) { return new List<Shortcode>(); } var shortcodes = new List<Shortcode>(); var matches = Regex.Matches(content, @"\[item id=(?<id>.*) fieldname=(?<fieldname>.*)\]", RegexOptions.Compiled | RegexOptions.IgnoreCase); foreach (var match in matches.OfType<Match>().Where(m => m.Success)) { shortcodes.Add(new Shortcode { Unexpanded = match.Value, Expanded = GetItem( match.Groups["id"].Value, match.Groups["fieldname"].Value) } ); } return shortcodes; } public string GetItem(string id, string fieldName) { if (!String.IsNullOrEmpty(id) && ID.IsID(id)) { var item = Context.Database.GetItem(ID.Parse(id)); if (item != null) { var name = fieldName.Replace("\"", String.Empty).Replace("'", String.Empty); if (item.Fields.Any(field => field.Name == name)) { return item.Fields[name].Value; } } } return String.Empty; } } }
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()
Wednesday, September 4, 2013
Sitecore PowerShell Extensions Unlock Items
Below is an example of how to unlock all items under the Content tree.
The following aliases or shortened commands were used:
# Find all the items under content recursively, then only return the properties you want. Here we only want items that are locked. gci master:\content -rec | where { $_.Locking.IsLocked() } | select Name, Id, @{n="IsLocked";e={$_.Locking.IsLocked()}}
The following aliases or shortened commands were used:
- gci = Get-ChildItem
- where = Where-Object
- select = Select-Object
# Unlock all the items. gci master:\content -rec | where { $_.Locking.IsLocked() } | % { $_.Locking.Unlock() }
Tuesday, September 3, 2013
Sitecore PowerShell Extensions Kick Users
Here's a quick way to kick users :)
# Use the static class to get the list of sessions then for each session kick the user using the session id. [Sitecore.Web.Authentication.DomainAccessGuard]::Sessions | % { [Sitecore.Web.Authentication.DomainAccessGuard]::Kick($_.SessionId) }
Saturday, August 31, 2013
Sitecore PowerShell Extensions Packages and Serialization
I'm at it again. Had fun today creating packages and serializing items with SPE.
Demo Code:
Demo Code:
# Serialization Get-Item -Path "master:\templates\spe\" | Serialize-Item -Recurse # Packages $name = "dinner" $package = New-Package -Name $name $source = Get-Item "master:\templates\spe" | New-ItemSource -Name "Dinner Plates" -InstallMode Overwrite -MergeMode Merge $package.Sources.Add($source) $package | Export-Package -Path "$name.xml" $package | Export-Package -Path "$name.zip" -Zip
Saturday, August 24, 2013
Sitecore PowerShell Extensions Creating Functions
Creating a function. Code below.
function Clear-SCArchive { <# .SYNOPSIS Clears entries from the archive. Defaults to a 30 retention period for the recyclebin. .EXAMPLE Remove all items 30 days or older. PS master:\> Clear-SCArchive .NOTES Michael West michaellwest.blogspot.com @MichaelWest101 about_Comment_Based_Help about_Comparison_Operators about_Functions_Advanced about_Functions_Advanced_Parameters about_Functions_CmdletBindingAttribute #> [CmdletBinding()] param( [ValidateNotNullOrEmpty()] [string]$Name = "recyclebin", [int]$Days = 30 ) $expired = [datetime]::Now.AddDays(-1 * [Math]::Abs($Days)) foreach($archive in Get-Archive -Name $Name) { $entries = $archive.GetEntries(0, $archive.GetEntryCount()) foreach($entry in $entries){ if($entry.ArchiveLocalDate -le $expired) { Write-Log "Removing item: $($entry.ArchivalId)" $archive.RemoveEntries($entry.ArchivalId) } else { Write-Verbose "Skipping $($entry.Name) on date $($entry.ArchiveLocalDate)" } } } }
Friday, August 23, 2013
Find Active Directory Users with Duplicate EmployeeId
Today I needed to create a report of all Active Directory users with duplicate EmployeeId. The first thing I thought to try was using the -Unique parameter. Let's see all the commands that support it.
This is great! I see two commands that will filter and return unique values. Let's see each in action.
Well what I really want to see is that 1 and 3 are returned for each instance. When talking in terms of Active Directory users, the EmployeeId will be duplicated but not the user, so this really isn't going to work.
In this example Sort-Object will work basically the same but also sort the list for us.
Another option is to go through all the users and tally up each occurrence of the EmployeeId and then filter them out.
Since we want the duplicates returned we can change the -eq to -gt like the following:
Still with me? The performance gain is from using the hashtable $ids; really good for creating a quick lookup table. So now that we know how to find the duplicates, let's try that in AD. I added a little error checking to make sure that the user actually has a value in the EmployeeId field (hashtables will also freakout with empty keys).
Finally, you can pipe the last line to Export-Csv to create your report.
Here is the above example in a form that uses the hashtable and one that users Group-Object (which might be a little faster).
PS C:\> Get-Command -ParameterName Unique CommandType Name ModuleName ----------- ---- ---------- Cmdlet Select-Object Microsoft.PowerShell.Utility Cmdlet Sort-Object Microsoft.PowerShell.Utility
This is great! I see two commands that will filter and return unique values. Let's see each in action.
PS C:\> 1,1,1,2,3,3 | Select-Object -Unique 1 2 3
Well what I really want to see is that 1 and 3 are returned for each instance. When talking in terms of Active Directory users, the EmployeeId will be duplicated but not the user, so this really isn't going to work.
In this example Sort-Object will work basically the same but also sort the list for us.
PS C:\> 3,3,2,1,1,1 | Sort-Object -Unique 1 2 3
Another option is to go through all the users and tally up each occurrence of the EmployeeId and then filter them out.
PS C:\> $values = 1,1,1,2,3,3 PS C:\> $ids = @{}; $values | ForEach-Object { $ids[$_] += 1 } PS C:\> $filteredValues = $values | Where-Object { $ids[$_] -eq 1 } PS C:\> $filteredValues 2
Since we want the duplicates returned we can change the -eq to -gt like the following:
PS C:\> $filteredValues = $values | Where-Object { $ids[$_] -gt 1 } PS C:\> $filteredValues 1 1 1 3 3
Still with me? The performance gain is from using the hashtable $ids; really good for creating a quick lookup table. So now that we know how to find the duplicates, let's try that in AD. I added a little error checking to make sure that the user actually has a value in the EmployeeId field (hashtables will also freakout with empty keys).
PS C:\> $users = Get-ADUser -Filter { Enabled -eq $true } -Properties EmployeeId PS C:\> $ids = @{}; $users | ForEach-Object { if($_.EmployeeId) { $ids[$_.EmployeeId] += 1 } } PS C:\> $filteredUsers = $users | Where-Object { if($_.EmployeeId) { $ids[$_.EmployeeId] -gt 1 } } PS C:\> $filteredUsers | Select-Object -Property SamAccountName, EmployeeId SamAccountName EmployeeId -------------- ---------- Michael.L.West 1234567 Michael.West 1234567
Finally, you can pipe the last line to Export-Csv to create your report.
Here is the above example in a form that uses the hashtable and one that users Group-Object (which might be a little faster).
Use Group-Object
$users = Get-ADUser -Filter { Enabled -eq $true } -Properties EmployeeId # Group by comparing the EmployeeId field $grouped = $users | Where-Object { [string]::IsNullOrEmpty($_.EmployeeId) } | Group-Object -Property EmployeeId | Where-Object { $_.Count -gt 1 } $filteredUsers = $grouped | ForEach-Object { $_ | Select-Object -ExpandProperty Group } $filteredUsers | Select-Object -Property SamAccountName, EmployeeId
Use Lookup Table
$users = Get-ADUser -Filter { Enabled -eq $true } -Properties EmployeeId # Increment a lookup table with the count $idLookup = $users | ForEach-Object { $idLookup = @{} } { if($_.EmployeeId) { $idLookup[$_.EmployeeId] += 1 } } { $idLookup } $filteredUsers = $users | Where-Object { if($_.EmployeeId) { $idLookup[$_.EmployeeId] -gt 1 } } $filteredUsers | Select-Object -Property SamAccountName, EmployeeId
Thursday, August 22, 2013
Sitecore PowerShell Extensions Basic Usage
Basic run through on using the Console and ISE from within Sitecore.
# Get details on how to use the Get-Item command Get-Help Get-Item # Get the list of items under home and filter by creator Get-ChildItem master:\content\home | Where-Object { $_."__Created By" -eq "sitecore\admin" } # Get the list of Sitecore PowerShell Extension commands Get-Command | Where-Object {$_.Implementingtype.FullName -match "Cognifide.PowerShell"} | Select-Object -Property Name | Format-Table
Tuesday, August 20, 2013
Sitecore PowerShell Extensions Introduction
Finally put together an introduction to the Sitecore PowerShell Extensions module.
Thursday, July 25, 2013
Active Directory - Find Difference Between Group Membership For User
While getting access transferred from one user to another, you may need to know how the group memberships are different between two users.
Import-Module ActiveDirectory $leaving = Get-ADUser -Identity John.Doe -Properties memberof | select -expand memberof $promoted = Get-ADUser -Identity Michael.West -Properties memberof | select -expand memberof Compare-Object -ReferenceObject $promoted -DifferenceObject $leaving
Tuesday, July 23, 2013
PowerShell Bible Scripture Function
I've been meaning to put this together for a while and just now got around to doing it. Here's a short function that calls the Bible.org Api for Bible scriptures. One idea I had was to plug this into my profile so that I could replace the Microsoft log with a scripture.
function Get-BibleVerse { <# .SYNOPSIS Calls the bible.org api and returns the specified scriptures. .DESCRIPTION Calls the bible.org api to return the specified book-chapter-verse, random verse, or verse of the day. .PARAMETER Random Indicates the scripture returned should be random. .PARAMETER VerseOfTheDay Indicates the scripture returned should be the verse of the day. .PARAMETER Book Indicates the book to return, such as Matthew, Marke, Luke, or John. .EXAMPLE PS C:\> Get-BibleVerse -Random .EXAMPLE PS C:\> Get-BibleVerse -VerseOfTheDay -Type Json -Formatting Plain .EXAMPLE PS C:\> Get-BibleVerse -Book Ephesians -Chapter 5 -Verse 25 -Type Json .NOTES Michael West 07.23.2013 http://michaellwest.blogspot.com .LINK http://labs.bible.org/api_web_service #> [CmdletBinding(DefaultParameterSetName="Default")] param( [Parameter(ParameterSetName="Random")] [switch]$Random, [Parameter(ParameterSetName="Votd")] [switch]$VerseOfTheDay, [Parameter(ParameterSetName="Default")] [ValidateNotNullOrEmpty()] [string]$Book="Genesis", [Parameter(ParameterSetName="Default")] [ValidateScript({$_ -gt 0})] [int]$Chapter = 1, [Parameter(ParameterSetName="Default")] [ValidateScript({$_ -gt -1})] [int]$Verse=1, [ValidateSet("Json","Xml","Text")] [string]$Type="Text", [ValidateSet("Full","Para","Plain")] [string]$Formatting="Plain" ) $url = "http://labs.bible.org/api/?passage=" if($PSCmdlet.ParameterSetName -eq "Votd") { $url += "votd" } elseif ($PSCmdlet.ParameterSetName -eq "Random") { $url += "random" } else { $url += "$($Book)+$($Chapter)" if($Verse) { $url += ":$($Verse)" } } $url += "&type=$($Type)&formatting=$($Formatting)" $url = $url.ToLower() $result = Invoke-WebRequest -Uri $url if($result) { $result.Content } }Update 07.24.2013 Add this to your profile to get the verse of the day.
$scripture = (Get-BibleVerse -VerseOfTheDay -Type Json | ConvertFrom-Json)[0] "$($scripture.bookname) $($scripture.chapter):$($scripture.verse) $($scripture.text)"
Thursday, July 18, 2013
Add Users to AD Group Using First Initial
Today at work we had a need to add users to specific Active Directory groups based on the first letter of the first name. We'll be using a plain text file as an example for the list of Active Directory identities. Save the following text into a file called names.txt:
John.Doe Jane.Doe Jane.SmithThen you will need to run this in the PowerShell ISE.
Import-Module ActiveDirectory # Each row of the text file will be consider one object. The object being the Active Directory identity (SamAccountName). $names = Get-Content c:\names.txt # Set this to $false when you are ready to make the changes. $whatIf = $true foreach ($name in $names) { $user = Get-ADUser -Filter { SamAccountName -eq $name } -Properties MemberOf if($user) { # The groups object will contain a list of Active Directory groups by their distinguished name. # (i.e. CN=GroupName_A-C,OU=Groups,OU=Company,DC=pri,DC=company,DC=com) $groups = $user | Select-Object -ExpandProperty MemberOf if(-not ($groups -like 'CN=GroupName_*')) { $groupName = '' switch -Regex($user.SamAccountName[0]) { # Match the first letter as a, b, or c. "[a-c]" { $groupName = 'GroupName_A-C' } # Match the first letter as d, e, f, or g. "[d-g]" { $groupName = 'GroupName_D-G' } "[h-k]" { $groupName = 'GroupName_H-K' } "[l-q]" { $groupName = 'GroupName_L-Q' } "[r-t]" { $groupName = 'GroupName_R-T' } "[u-z]" { $groupName = 'GroupName_U-Z' } } if($groupName) { "Adding $($user.SamAccountName) to the group $($groupName)" Add-ADGroupMember -Identity $groupName -Members $user.SamAccountName -WhatIf:$whatIf } } else { "Skipping $($user.SamAccountName) because they are already in the group $($groupName)" } } else { "$($name) does not exist" } }
Monday, July 8, 2013
PoweShell Script Module
I put together a PowerShell Script Module some time ago and thought I would make it available for others. Hope it helps give you some ideas on creating your own.
Click for more details.
Thursday, June 27, 2013
CSharp String to SQL Table
I have a problem at work in which I need to convert a comma separated string into a SQL temp table. You can easily add this to a function.
Output:
DECLARE @LoginNames VARCHAR(max) SET @LoginNames = 'Michael,Rebecca' -- Create a temp table with a single column called LoginName DECLARE @temp AS TABLE (LoginName NVARCHAR(255)) IF ISNULL(@LoginNames, '') <> '' BEGIN DECLARE @s NVARCHAR(max) WHILE LEN(@LoginNames) > 0 BEGIN IF CHARINDEX(',', @LoginNames) > 0 BEGIN SET @s = LTRIM(RTRIM(SUBSTRING(@LoginNames, 1, CHARINDEX(',', @LoginNames) - 1))) -- After parsing a single value from the list, insert into the temp table INSERT INTO @temp (LoginName) VALUES (@s) SET @LoginNames = SUBSTRING(@LoginNames, CHARINDEX(',', @LoginNames) + 1, LEN(@LoginNames)) END ELSE BEGIN SET @s = LTRIM(RTRIM(@LoginNames)) -- After parsing a single value from the list, insert into the temp table INSERT INTO @temp (LoginName) VALUES (@s) SET @LoginNames= '' END END END SELECT LoginName FROM @temp
Output:
LoginName |
---|
Michael |
Rebecca |
Tuesday, May 7, 2013
Scripting Games 2013 Advanced Event 2 - My Submission
If you have not already, I highly recommend you work on the events for the Scripting Games. I feel like I'm learning so much within a few short days mainly due to the fact that I have very specific requirements outlined by the event, as well as knowing that tons of people will potentially see my submissions. Today I'll be talking about it during the Lunch-n-Learn I host at work, so seeing constructive and accurate criticism is welcomed (username michaellwest). Here is what I have submitted, please let me know your thoughts on how I can improve the script.
- The begin scriptblock contains a hashtable of settings to use for the function. The keys represent the Cim class name and the values represent the properties to return. You can use strings, hashtables, and scriptblocks.
- Use CimSessionOption with the Dcom protocol to more reliably query Windows Server 2000-2008.
- The nested foreach loops are not that great, however the keys and properties are few so the performance is still fine. Get-CimInstance is what takes a long time.
function Get-ServerInventory { <# .SYNOPSIS Performs a hardware inventory on the specified server(s). .DESCRIPTION The values returned by the inventory process may be enhanced by adding to the settings hashtable in the begin scriptblock. The settings key is the class name. The settings values supported include string, hashtable, and scriptblock. .PARAMETER ComputerName Indicates the server(s) to perform a hardware inventory. The default value is localhost. .EXAMPLE Perform an inventory on localhost. PS C:\> Get-ServerInventory TotalPhysicalMemory : 21356912640 ProcessorName : Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz Version : 6.1.7601 SerialNumber : 00371-OEM-8992671-00008 ComputerName : WIN7DEV01 Cores : 4 Sockets : 1 .EXAMPLE Perform an inventory on 1-N servers with an array or using Get-Content. PS C:\> "WIN2K01","WIN2K02","WIN2008R201" | Get-ServerInventory | Format-Table -AutoSize TotalPhysicalMemory ProcessorName Version SerialNumber ComputerName Cores Sockets ------------------- ------------- ------- ------------ ------------ ----- ------- 4294148096 Intel(R) Xeon(R) CPU E5-2680 0 @ 2.70GHz 5.2.3790 69712-640-5906017-45214 WIN2K01 1 1 2146861056 Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz 5.2.3790 69712-641-5611134-45717 WIN2K02 1 1 4294500352 Intel(R) Xeon(R) CPU E5-2680 0 @ 2.70GHz 6.1.7601 55041-266-0135507-84842 WIN2008R201 1 1 .LINK Windows Server 2003 incorrectly reports the number of physical multicore processors or hyperthreading-enabled processors. Apply the below hotfix to correct the reported issue. http://support.microsoft.com/kb/932370 .LINK Example on retrieving the CPU count. http://www.sql-server-pro.com/physical-cpu-count.html #> [CmdletBinding()] param( [Parameter(ValueFromPipeline=$true)] [ValidateNotNullOrEmpty()] [string[]]$ComputerName=$env:COMPUTERNAME ) begin { $settings = @{ "Win32_OperatingSystem" = @("Version","SerialNumber") "Win32_ComputerSystem" = @({param($result,$output) $output["Capacity"] = $result | Measure-Object -Property Capacity -Sum | Select-Object -ExpandProperty Sum}) "Win32_Processor" = @(@{n="ProcessorName";e={$_.Name}}, { param($result,$output) $processors = @($result) if ($processors[0].NumberOfCores) { $output["Cores"] = $processors.Count * $processors[0].NumberOfCores } else { $output["Cores"] = $processors.Count } $output["Sockets"] = @($processors | Where-Object {$_.SocketDesignation} | Select-Object -Unique).Count }) } } process { $sessions = $ComputerName | Select-Object @{n="ComputerName";e={$_}} | New-CimSession -SessionOption (New-CimSessionOption -Protocol Dcom) foreach($session in $sessions) { $output = @{} foreach($key in $settings.Keys) { $result = Get-CimInstance -CimSession $session -ClassName $key $output["ComputerName"] = $result.PSComputerName foreach($property in $settings[$key]) { if($property -is [string]) { $output[$property] = $result.$property } elseif ($property -is [scriptblock]) { Invoke-Command -ScriptBlock $property -ArgumentList $result, $output } elseif ($property -is [hashtable]) { ($result | Select-Object -Property $property).PSObject.Properties | ForEach-Object {$output[$_.Name] = $_.Value } } } } [PSCustomObject]$output Remove-CimSession -CimSession $session } } }
Friday, April 26, 2013
Embedding Csharp in PowerShell Script
I wanted to use a "using block" found in C# to dispose of objects in PowerShell such as Streams or other object types that require the calling of Dispose.
After seeing different examples here is where I stopped. I made some minor tweaks.
- Begin by creating a class in C#. You can also save the code in a separate file such as Code.cs. See help Add-Type -Examples for additional examples. The class must also inherit from System.IDisposable, otherwise the using-block function will complain with something like 'using-block : Cannot process argument transformation on parameter 'InputObject'. Cannot convert the "Code" value of type "Code" to type "System.IDisposable".'
- Create your using block with the instantiation of a new object in parentheses.
- Finally, in the script block place your needed logic.
Add-Type @" using System; public class Code : IDisposable { public Code() { Name = "Michael"; } public string Name { get; set; } public bool IsDisposed { get; set; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!IsDisposed) { IsDisposed = true; } } } "@ function using-block { param ( [System.IDisposable]$InputObject = $(throw "The parameter -inputObject is required."), [ScriptBlock]$ScriptBlock = $(throw "The parameter -scriptBlock is required.") ) try { & $ScriptBlock } finally { if ($InputObject) { if ($InputObject.PSBase) { $InputObject.PSBase.Dispose() } else { $InputObject.Dispose() } } } } using-block($c = New-Object Code) { $name = $c.Name $name # Michael $c.IsDisposed # False } $name # Not in this scope so no value $c.IsDisposed # TrueThis may not be the most elegant approach but it served it's purpose.
Sunday, April 7, 2013
PowerShell Module In Session
I found it a little difficult to bring in functions into a session so I thought this would help others with what helps me get the job done.
The video goes from creating a script module to importing that module into a session.
The video goes from creating a script module to importing that module into a session.
Tuesday, April 2, 2013
Run with PowerShell Context Menu
Today I was working on our automated build process at work, and found myself running a batch file in a console window that I wanted to remain open. I setup a context menu item associated with .bat files which launches with PowerShell.
Here are the steps:
Here is an example of the output:
Here are the steps:
# We need to create our keys under HKEY_CLASSES_ROOT, which by default has not associated PSDrive. New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT # Set the current location to the new drive. cd HKCR: # Set the current location to the shell key for .bat files. cd '.\batfile\shell' # Create a new key called "Run with PowerShell" New-Item -Path 'Run with PowerShell' # Set the current location to the new key. cd '.\Run with PowerShell' # Create a new key called "command", which will contain the reference to PowerShell. New-Item -Path 'command' cd '.\command' # Create a new "(default)" string with the command to execute PowerShell. The "%1" contains the path to the .bat file. New-ItemProperty -Path '.' -Name '(default)' -Value 'C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe "-nologo" "-noexit" "-command" "& {%1}"'
Here is an example of the output:
PS C:\> New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT Name Used (GB) Free (GB) Provider Root CurrentLocation ---- --------- --------- -------- ---- --------------- HKCR Registry HKEY_CLASSES_ROOT PS C:\> cd HKCR:\batfile\shell PS HKCR:\batfile\shell> New-Item -Path 'Run with PowerShell' Hive: HKEY_CLASSES_ROOT\batfile\shell Name Property ---- -------- Run with PowerShell PS HKCR:\batfile\shell> cd '.\Run with PowerShell' PS HKCR:\batfile\shell\Run with PowerShell> New-Item -Path 'command' Hive: HKEY_CLASSES_ROOT\batfile\shell\Run with PowerShell Name Property ---- -------- command PS HKCR:\batfile\shell\Run with PowerShell> cd '.\command' PS HKCR:\batfile\shell\Run with PowerShell\command> New-ItemProperty -Path '.' -Name '(default)' -Value 'C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe "-nologo" "-noexit" "-command" "& {%1}"' (default) : C:\WINDOWS\SysWow64\WindowsPowerShell\v1.0\powershell.exe "-nologo" "-noexit" "-command" "& {%1}" PSPath : Microsoft.PowerShell.Core\Registry::HKEY_CLASSES_ROOT\batfile\shell\Run with PowerShell\command PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CLASSES_ROOT\batfile\shell\Run with PowerShell PSChildName : command PSDrive : HKCR PSProvider : Microsoft.PowerShell.Core\Registry
Wednesday, March 27, 2013
PowerShell Github Projects
I've been working on a few projects in PowerShell. Here is the source code on Github for those interestered.
PowerShell with GUI in Xaml
PowerShell Deployment
PowerShell with GUI in Xaml
PowerShell Deployment
Saturday, March 23, 2013
Discover PowerShell - Episode 5
Introduction on using the splatting feature in Windows PowerShell 3.
Disable PowerShell Remoting
Here are a few quick steps to "undo" the default changes performed by Enable-PSRemoting.
PS C:\> Disable-PSRemoting -Force WARNING: Disabling the session configurations does not undo all the changes made by the Enable-PSRemoting or Enable-PSSessionConfiguration cmdlet. You might have to manua lly undo the changes by following these steps: 1. Stop and disable the WinRM service. 2. Delete the listener that accepts requests on any IP address. 3. Disable the firewall exceptions for WS-Management communications. 4. Restore the value of the LocalAccountTokenFilterPolicy to 0, which restricts remote access to members of the Administrators group on the computer. PS C:\> winrm delete winrm/config/listener?address=*+transport=HTTP PS C:\> Stop-Service winrm PS C:\> Set-Service -Name winrm -StartupType Disabled PS C:\> Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System -Name LocalAccountTokenFilterPolicy -Value 0 -Type DWord
Discover PowerShell - Episode 4
I've been playing around with PowerShell remoting quite a bit lately and I thought making a tutorial on the basics would help solidify my understanding. Plus, I like teaching so why the heck not?!
Saturday, March 16, 2013
Determine If A Command Exists In PowerShell
Ed Wilson "The Scripting Guy" posted a great article a while back on how to determine if a command exists here. Here is another approach that I came up with that morning.
function Test-Command { param($Command) $found = $false $match = [Regex]::Match($Command, "(?<Verb>[a-z]{3,11})-(?<Noun>[a-z]{3,})", "IgnoreCase") if($match.Success) { if(Get-Command -Verb $match.Groups["Verb"] -Noun $match.Groups["Noun"]) { $found = $true } } $found }
Here is a breakdown of the regular expression used.
- The first group in the expression is for the verb, which is 3 to 11 characters long (consult the approved verb list).
- The second group in the expression is for the noun, which can be 3 or more characters long. I limit the acceptable text to only alphabetical characters and by adding the "IgnoreCase" option we can just use "a-z".
So what would an article be without a quick example.
PS C:\> Test-Command -Command Get-Process True PS C:\> Test-Command -Command Get-Proc* False
Finally, if you would like a shortcut which expects an exact match you can try this:
PS C:\> [bool](Get-Command -Name Get-Process -ea 0) True
Friday, March 15, 2013
Add Font to PowerShell Console
I saw an article about Adobe's release of a new font called Source Code Pro which was designed in part to help reduce the confusion between certain characters. I thought I would give it a try. After copying the .ttf files to C:\Windows\Fonts, I realized that the font needed to be added in the registry, so here are some steps to get you going.
Change the provider to the registry HKLM: which will get you to HKEY_LOCAL_MACHINE.
Navigate to the Console key, then list the properties for TrueTypeFont.
Note: I removed some of the extra entries returned by Get-ItemProperty for clarity.
PS C:\> cd HKLM: PS HKLM:\> cd '.\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console' PS HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console> Get-ItemProperty -Path TrueTypeFont 0 : Lucida Console 00 : Consolas PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console PSChildName : TrueTypeFont PSDrive : HKLM PSProvider : Microsoft.PowerShell.Core\Registry
Add the new string value. Here I see that 0 and 00 are already used, so we're going to use 000. Then verify the new string exists.
PS HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console> Set-ItemProperty -Path TrueTypeFont -Name 000 -Value 'Source Code Pro' PS HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console> Get-ItemProperty -Path TrueTypeFont 0 : Lucida Console 00 : Consolas 000 : Source Code Pro PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console PSChildName : TrueTypeFont PSDrive : HKLM PSProvider : Microsoft.PowerShell.Core\Registry
Let's try and programmatically set the new font in the console.
Create a new PSDrive for the HKEY_USERS hive.
Change to the HKU: drive.
Change to the SID for the current user.
Set the Console property for FaceName to the new font.
PS C:\> New-PSDrive HKU Registry HKEY_USERS Name Used (GB) Free (GB) Provider Root CurrentLocation ---- --------- --------- -------- ---- --------------- HKU Registry HKEY_USERS PS C:\> cd HKU: PS HKU:\> cd (New-Object System.Security.Principal.NTAccount($env:USERNAME)).Translate([System.Security.Principal.SecurityIdentifier]).Value PS HKU:\S-1-5-21-3501008845-2378336731-207489776-1001> PS HKU:\S-1-5-21-3501008845-2378336731-207489776-1001> Set-ItemProperty -Path Console -Name FaceName -Value 'Source Code Pro'
Now you just need to restart your console and you're good to go!
Saturday, March 9, 2013
Get ValidateSet or Enum Options in PowerShell Command
Edit: I renamed the function because I didn't really like the name.
I've seen a few articles on how to get the valid parameter values for a command, however I thought they were a bit messy. Take for example this:
Programmatic way to get valid string values for a parameter
PS C:\Users\Michael> Set-ExecutionPolicy -ExecutionPolicy WrongValue Set-ExecutionPolicy : Cannot bind parameter 'ExecutionPolicy'. Cannot convert value "WrongValue" to type "Microsoft.PowerShell.ExecutionPolicy". Error: "Unable to match the identifier name WrongValue to a valid enumerator name. Specify one of the following enumerator names and try again: Unrestricted, RemoteSigned, AllSigned, Restricted, Default, Bypass, Undefined" At line:1 char:38 + Set-ExecutionPolicy -ExecutionPolicy WrongValue + ~~~~~~~~~~ + CategoryInfo : InvalidArgument: (:) [Set-ExecutionPolicy], ParameterBindingException + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.SetExecutionPolicyCommandAs you can see, you have to sift through the error message to get the valid values. On top of that, you can't do anything with the data because it's trapped in a long string of text. This morning I came up with this function to solve that problem for me.
function Get-ParameterOption { param( $Command, $Parameter ) $parameters = Get-Command -Name $Command | Select-Object -ExpandProperty Parameters $type = $parameters[$Parameter].ParameterType if($type.IsEnum) { [System.Enum]::GetNames($type) } else { $parameters[$Parameter].Attributes.ValidValues } }Here are some examples of using it. Please note that there really isn't any error checking, that will be in the next version :) This example is for Set-ExecutionPolicy:
PS C:\Users\Michael> Get-ParameterOption -Command Set-ExecutionPolicy -Parameter ExecutionPolicy Unrestricted RemoteSigned AllSigned Restricted Default Bypass UndefinedThis example is for a custom function which uses the ValidateSet attribute.
function Do-Something { param( [ValidateSet("Low","Medium","High")] [string]$Option ) "Something happened" }
PS C:\Users\Michael> Get-ParameterOption -CommandName Do-Something -Parameter Option Low Medium High
PS C:\> Get-ParameterOption -Command Get-Command -Parameter ErrorAction SilentlyContinue Stop Continue Inquire IgnoreAfter I did a little more research, I guess Jeffrey Snover beat me to it.
Programmatic way to get valid string values for a parameter
Wednesday, February 27, 2013
Discover PowerShell - Episode 3
Final post of the training series tonight. I've started giving these presentations at work and I'm starting feel like I know what I'm talking about. Just a feeling, although it could be the dinner I ate.
Discover PowerShell - Episode 2
I found that making these videos at home is far more relaxing than trying to sit in my cube at work. No strange looks, especially when I restart the recording 5 or 6 times and repeat myself.
Discover PowerShell - Episode 1
I started a training series on using Windows PowerShell 3. The videos closely follow the book by Don Jones, Learn Windows PowerShell 3 in Month of Lunches.
I hope you enjoy them. Feedback always welcome.
I hope you enjoy them. Feedback always welcome.
Subscribe to:
Posts (Atom)