Top Posts
Categories
- This seems promising - free virt training from Microsoft w/ private cloud track… http://t.co/sKIE6Kar 3 days ago
IT Notes from the Powertoe – Tome Tanasovski
It’s quite common to receive an e-mail from someone that has a list of computers that need a script run against it – or perhaps a list of perfmon counters that need to be collected – or even a list of usernames that someone needs you to pull from AD in order to create a custom report about the user and his attributes. There are a few ways to put this data into your scripts. Probably the most common method I have seen is to put this data into a file and run Get-Content file.txt. This works fine, but I generally just need to do a bit of one-off scripting and want to bang it out quick. When that happens I throw the list into a here string and break it up with the -split operator:
$computers = @" Computer1 Computer2 Computer3 Computer4 "@ -split '\r\n'
This creates a collection of strings where each line has its own string.
PS C:\> $computers.gettype() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True String[] System.Array
Now you can throw this collection into a foreach loop
foreach ($computer in $computers) {
#Do something to $computer
}
or better yet you can throw it at a parameter that takes a collection like Invoke-Command
Invoke-Command -Computername $computers -Scriptblock {Get-Process}
Nice! I just spanned out Get-Process to the four computers in my list!
I have a love/hate relationship with the new ISE. I’ll spare any discussion on the topic until after the CTP is no longer a CTP. In the meantime, I’ll just leave you with a quick script to help you if you are as resistant to change as I am with my beloved ISE.
In the new ISE the output pane and command pane are one. They happen to look like this:

For my eyes, I prefer the go-lightly look of the v2 ISE. If you feel the same way, you can have everything you want by running the following script:
$psise.Options.OutputPaneBackgroundColor = "#FFF0F8FF"
$psise.Options.OutputPaneForegroundColor = "#FF000000"
$psise.Options.OutputPaneTextBackgroundColor = "#FFF0F8FF"
foreach ($key in ($psise.Options.ConsoleTokenColors.keys |%{$_.tostring()})) {
$color = $psise.Options.TokenColors.Item($key)
$newcolor = [System.Windows.Media.Color]::FromArgb($color.a,$color.r,$color.g,$color.b)
$psise.Options.ConsoleTokenColors.Item($key) = $newcolor
}
Now doesn’t that look better – I mean more familiar
The above applies the script pane’s token colors to the command pane. Token colors are new to the command pane in V3.

Two additional notes:
1) If you want to restore back to the original look and feel that was shipped, you can use the following:
$psise.Options.RestoreDefaults() $psise.Options.RestoreDefaultConsoleTokenColors()
2) Everything in this article can now be done in ISE via their new color themes, but again let’s wait to see what happens during RTM. However, you can play with it yourself for now by clicking Tools->Options… and then clicking the Colors and Fonts tab in ISE.
So CTP 1 for PowerShell v3 was released. Go get it now. I will use another hash tag for this called v3CTP1 so that I can quickly fix these posts when I go back after V3 is RTM.
So, with so much to talk about, I’m going to show something simple that I think is madly madly cool! Out-GridView now has a PassThru parameter. What does it mean, what does it mean?
Try the following:
Get-Process |Out-GridView -PassThru |Select Name
You’ll see your normal Out-GridView, but you’ll also see an OK and Cancel button int he bottom right.
What does it mean?
Filter the contents of the gridview to display things you are interested in, then click on a few rows. When you have selected a few, click OK! You have just passed the objects that you are interested in through the pipeline to the next cmdet which happens to be Select Name. What an amazing cmdlet! The ability to have the operator of your script use the filtering and sorting of Out-GridView to choose data that should be processed!
If you are not aware, a developer version of Windows 8 was released at the build conference. For the purpose of this blog I will use a specific tag (3.0 Win 8 Developer Build) for these posts so that I can remove and clean them up once PowerShell 3.0 is RTM.
I was looking at the new variables with dir variable: in PowerShell 3.0 and one caught my eye: $PSDefaultParameterValues
Interesting. The first thing to do is inspect it. The following shows the trail of that inspection:
PS C:\Users\toenuff.Win8> $PSDefaultParameterValues
_____________________________________________________________________________________________________
PS C:\Users\toenuff.Win8> $PSDefaultParameterValues.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False DefaultParameterDictionary System.Collections.Hashtable
_____________________________________________________________________________________________________
PS C:\Users\toenuff.Win8> $PSDefaultParameterValues |gm
TypeName: System.Management.Automation.DefaultParameterDictionary
Name MemberType Definition
---- ---------- ----------
Add Method System.Void Add(System.Object key, System.Object value)
ChangeSinceLastCheck Method bool ChangeSinceLastCheck()
Clear Method System.Void Clear()
Clone Method System.Object Clone()
Contains Method bool Contains(System.Object key)
ContainsKey Method bool ContainsKey(System.Object key)
ContainsValue Method bool ContainsValue(System.Object value)
CopyTo Method System.Void CopyTo(array array, int arrayIndex), System.Vo...
Equals Method bool Equals(System.Object obj)
GetEnumerator Method System.Collections.IDictionaryEnumerator GetEnumerator(), ...
GetHashCode Method int GetHashCode()
GetObjectData Method System.Void GetObjectData(System.Runtime.Serialization.Ser...
GetType Method type GetType()
OnDeserialization Method System.Void OnDeserialization(System.Object sender)
Remove Method System.Void Remove(System.Object key)
ToString Method string ToString()
Item ParameterizedProperty System.Object Item(System.Object key) {get;set;}
Count Property System.Int32 Count {get;}
IsFixedSize Property System.Boolean IsFixedSize {get;}
IsReadOnly Property System.Boolean IsReadOnly {get;}
IsSynchronized Property System.Boolean IsSynchronized {get;}
Keys Property System.Collections.ICollection Keys {get;}
SyncRoot Property System.Object SyncRoot {get;}
Values Property System.Collections.ICollection Values {get;}
I’m not sure what DefaultParameterDictionary is, but it’s derived from a hash table. So, what happens when you try to set some values in there?
PS C:\Users\toenuff.Win8> $PSDefaultParameterValues.tome = 'blah'
The key 'tome' has an invalid format. The key must consist of one command name and one parameter name
separated only by a colon (CommandName:ParameterName). The command name and/or the parameter name can
be enclosed in individual quotation marks ("CommandName":"ParameterName"), but the entire key cannot be
enclosed in quotation marks. To disable the $PSDefaultParameterValues feature, set the key/value pair
to Disabled=$true.
At line:1 char:1
+ $PSDefaultParameterValues.tome = 'blah'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidOperation
JACKPOT!!!! We learn that the key name needs to be command:parametername and we learn that we can disable this feature by setting $PSDefaultParameterName.Disabled = $true.
It looks like we can set default parameter values now. Just choose the cmdlet along with parameter name as follows:
$PSDefaultParameterValues.('Invoke-Command:Credential') = (get-credential)
Now every time I run Invoke-Command it uses the credentials I specified earlier without having to ever use the -Credential parameter again. Will this feature make the final cut? I’m not sure. It does have security implications. What if a rogue module developer attacked you by setting default parameters for a cmdlet? Then again, a rogue module developer could do a lot worse than this. If nothing else, there is certainly practical joke material here when we start modifying our friend’s profiles on April 1st. I’m curious. What do you think we can do with this feature? What cmdlets are screaming for this to be used in your profile?
Here’s my list:
Well, I’ve been quiet in the blogland, quiet in the forums, and finally done with everything for the book. So, where have I been? Besides working and finally having time to spend with my family, I have put together a little super secret project. Starting this moment, I have released the PowerShell Cmdlet of the Day Podcast. The pilot episode has been released on Get-Input.
I am a huge fan of the short-form podcasts. I love listening to NPR’s Sunday Puzzle and Grammar Girl. I’ve also used to love the Nasa podcast. I thought it was high time the PowerShell community got treated to something like this. So, we’ll see where it goes. My first podcast (The Toe Show back in 2003/2004) only had 11 episodes. Fortunately for me, I’ve already recorded almost that many for this show in order to stay ahead of the release curve, but my resolve has obviously not yet been tested. After this week, I expect to release an episode twice a week. The second episode will be released on Sunday night/Monday morning and the next few episodes will be about the Group Policy module that now ships with Server.
One more huge announcement. I will be on the PowerScripting podcast tomorrow night 8/18/2011. There is a live taping at 9:30pm or you can pick up the episode next week some time (It should be episode 159). I’m hugely excited to be on the show; it’s my first time on!
So, as the new voice in your head – let me type “Goodbye”
Just like everyone else in the Windows PowerShell community I found what James Brundage and Joel “Jaykul” Bennett were doing with scripting UIs extremely interesting. However, I found the whole process cumbersome for some reason. Perhaps it was due to “meh” documentation. Perhaps it was due to my brain just not being ready to absorb it. Perhaps it was due to the fact that I can develop a winform really quickly in something like Primal Forms. Whatever it was, it just didn’t seem like it was worth my effort. Even after I watched James give a presentation on scripted GUIs at this year’s Techstravaganza in NYC I saw the potential, but I did not feel compelled to waste any more time with WPK than the few days I gave it when the PowerShell Pack was released. Recently, the two major players in the scripted UI space joined forces with Doug Finke and developed a new set of cmdlets that took the great elements of each implementation of interfacing with WPF and combined them into one extremely sleek and impressive module. In my mind this must have played out like this: Doug Finke, successful enterprise-level developer who focuses on automation in the development space grabbed two mad scientists by the back of their necks and forced them down from the stratosphere where their genius lives to focus them to work in the world with the rest of us. Perhaps there were chains involved? Perhaps shock treatment? Perhaps it didn’t even happen like that and was more like James’s blue ox cut down Jaykul’s apple tree and little red riding Doug couldn’t tell a lie. We’ll let the myth of the why perpetuate. What’s important is that I am impressed with their collaborative effort, and I can’t wait to share what I did in only 60 minutes with the new stuff.
If you are not aware of what I’m talking about and these names just sound like nonesense to you welcome to the niche world of scripted UIs.
The promise is simple. Dynamically generated user interfaces that adapt to your needs. I had the rare opportunity to see some of James Brundage’s WPK-based cmdlets that would convert seemingly simple bits of code into beautiful graphics and doo dahs and woo hoos. He was developing a library of these to help him very rapidly develop based off of these prototypes. It appears that now that this is within all of our reach.
I won’t be going into the introduction of how to use this module. I’ll leave that to you. There’s a few places to start though.
The one thing you’ll notice when going through the sample code is that everything is written in scriptblocks. This is the power of the toolkit. It is based on Ruby Shoes – a toolkit that was created to make UIs for Ruby. The syntax looks nearly identical. But that’s a digression. More importantly is that scriptblocks can easily be dynamic because they are just code. A while back I posted this article that talks about the world of dynamic scriptblocks in Windows PowerShell. I took that and realized that I could easily apply it to the sample in Joel’s tutorial that stood out the most to me: The simple form that displays label/textbox, label/textbox, label/textbox, etc, followed by a button to submit. The magic was that not only was this being generated, but after hitting submit it returned a hash table that had the values that were entered in the text boxes. So, I said to myself, “Well I want this dynamic. I want to pass a random number of fields and have it generate this simple form. The result is the function below New-SimpleForm.
Import-Module showui function New-SimpleForm { param( [Parameter(Mandatory=$true, ValueFromPipeline=$true)] [psobject]$Fields, [Parameter(Mandatory=$false)] [string]$Name = 'Simple ShowUI Form', [Parameter(Mandatory=$false)] [int] $MinWidth = 250 ) BEGIN { $allfields = @() } PROCESS { $allfields += $Fields } END { $txtblock = "" $row = 0 foreach ($field in $allfields) { $boxlabel = $field -replace '\W' ,'_' $txtblock += "Label '$field' -row $row `r`n" $txtblock += "TextBox -Name '$boxlabel' -Column 1 -Row $row`r`n" $row++ } $txtblock += @" Button "Submit" -IsDefault -On_Click { Get-ParentControl | Set-UIValue -passThru | Close-Control } -Row $row -column 1 "@ $scriptblock = $ExecutionContext.InvokeCommand.NewScriptBlock($txtblock) $onloaded = $ExecutionContext.InvokeCommand.NewScriptBlock("`$$($allfields[0] -replace '\W', '_').Focus()") #$scriptblock grid -ControlName $Name -Columns Auto,* -Rows ($allfields.count + 1) -MinWidth $MinWidth $scriptblock -show -On_Loaded $onloaded } }
New-SimpleForm can be called like this:
@("Name", "E-mail", "Date of Birth") | New-SimpleForm
The above will produce this form:
The output will be a hash table that looks like this:
Name Value ---- ----- Name Tome Tanasovski Date_of_Birth 5/11/1976 E_mail toenuff@somedomain.com
Alternatively you could supply the hash table right into a psobject if you prefer:
new-object psobject -Property (@("Name","E-mail","Date of Birth") |New-SimpleForm)
The output of the above looks like this:
Name Date_of_Birth E_mail ---- ------------- ------ Tome Tanasovski 5/11/1976 toenuff@somedomain.com
Not bad for only 60 minutes of tinkering. Now I have a utility webform that I can use to retrieve user input extremely quickly. Obviously, validation has to come after the fact, but that’s not so bad. Whew! Feels good to be playing with interesting things!
———————-Update 7/6/2011, 8:55 PM————————–
ShowUI version 1.1 was just released with a cmdlet called Get-Input. This takes my idea and blows it out of the water! Check out the video of it here.
I recently was handed these requirements for a task at work:
I decided to add an additional requirement:
Before I show you how I tackled this problem I’d like to be clear that I realize that there is no such thing as perfect security and encryption of a password in a script. It’s usually better to use something like schtasks to store the credentials and provide a user permissions to launch the script via the task. In my case I wanted the user to easily be able to modify the arguments passed to the script. So really my intention is not to secure the password from the people using it, but to make it very difficult for someone outside of the group who will use the script to read the text in the script and be able to find the password.
If you are not aware, it is very easy to do this per user using a SecureString. There are two Convert cmdlets that allow us to convert to and from a secure string: ConvertTo-SecureString and ConvertFrom-SecureString. For example, this is an extremely common way that people store a password to disk:
(get-credential).password|convertFrom-SecureString|set-content c:\password.txt
The way to load this password from disk is as follows:
$user = 'domainA\Tome' $cred = New-Object System.Management.Automation.PsCredential $user,(Get-Content c:\password.txt| ConvertTo-SecureString)
The above two examples require the commands to be run using the same credentials in order for it to work properly. However, ConvertTo-SecureString and ConvertFrom-SecureString also have a -key parameter so that you can perform these conversions by different users on the same computer or on a different computer altogether. The problem with using the -Key parameter is that you need to store the key within your script. Hardly very secure when the entire point of this exercise is to keep password out of the hands of someone who is able to read the text in the script.
In the end my solution used the Key parameter of the SecureString cmdlets, but only to ensure that the password is never in plain text in memory. The Key is stored in the script, but it is the converted SecureString that I encrypt using RSA encryption with a machine key. Here are the high-level steps that writes the password encrypted to disk.
$key = (2,3,56,34,254,222,1,1,2,23,42,54,33,233,1,34,2,7,6,5,35,43,6,6,6,6,6,6,31,33,60,23) $pass = Read-Host -AsSecureString $securepass = $pass |ConvertFrom-SecureString -Key $key $bytes = [byte[]][char[]]$securepass $csp = New-Object System.Security.Cryptography.CspParameters $csp.KeyContainerName = "SuperSecretProcessOnMachine" $csp.Flags = $csp.Flags -bor [System.Security.Cryptography.CspProviderFlags]::UseMachineKeyStore $rsa = New-Object System.Security.Cryptography.RSACryptoServiceProvider -ArgumentList 5120,$csp $rsa.PersistKeyInCsp = $true $encrypted = $rsa.Encrypt($bytes,$true) $encrypted |Export-Clixml 'C:\Dropbox\My Dropbox\scripts\word.xml'
$encrypted = Import-Clixml 'C:\Dropbox\My Dropbox\scripts\word.xml' $key = (2,3,56,34,254,222,1,1,2,23,42,54,33,233,1,34,2,7,6,5,35,43,6,6,6,6,6,6,31,33,60,23) $csp = New-Object System.Security.Cryptography.CspParameters $csp.KeyContainerName = "SuperSecretProcessOnMachine" $csp.Flags = $csp.Flags -bor [System.Security.Cryptography.CspProviderFlags]::UseMachineKeyStore $rsa = New-Object System.Security.Cryptography.RSACryptoServiceProvider -ArgumentList 5120,$csp $rsa.PersistKeyInCsp = $true $password = [char[]]$rsa.Decrypt($encrypted, $true) -join "" |ConvertTo-SecureString -Key $key $cred = New-Object System.Management.Automation.PsCredential 'tome',$password Start-Process -Credential $cred -FilePath 'powershell.exe' -ArgumentList '-noprofile','-file','"c:\dropbox\my dropbox\scripts\t.ps1"', "blah"
The full scripts are not actually the complete scripts I used. I wound up creating wrapper scripts for each script I needed the users to run with parameters. The wrapper scripts had the same parameters and some logic within them.
I know there are some shortcuts you can take, e.g., you can convert strings to and from bytes using the System.Text functions. I also realize that it makes more sense to encrypt the 32 byte key using RSA rather than encrypting the SecureString, but to be honest, I realized this a bit late. I left it as is figuring that an encrypted 192 byte string using a larger RSA key is probably better than 32 bytes encrypted with a smaller key, but it probably doesn’t matter much either way. You take a bit of a hit when you generate the larger RSA key, but it’s really negligible. In the end, I created something that is working fine for me using the techniques that I was quickest with.
It may not be perfect in a security conscious world, but it met my requirements and is working nicely for me.
Oh, one final note. If you wanted to use this technique for users who are not administrators on the server you only need to grant them access to the Machine Key file created in c:\Documents and Settings\All Users\Application Data\Microsoft\Crypt\RSA\MachineKeys.
I was just browsing Osin’s latest contribution to the community, pseventing plus, which allows you to add hotkey events to your PowerShell sessions. I was looking at his samples and found the handy one to start notepad with elevated privileges to open your hosts file. If you are unaware, there is a -Verb parameter with Start-Process that will accept “Runas” as an argument to start a new process with elevated privileges. If you wanted to open your hosts file with notepad the command would be:
Start-Process -Verb Runas notepad c:\windows\system32\drivers\etc
This is already pretty well documented, but I realized that I was foolish because I never wrapped this in a function and put it in my profile. so I did it, and it is now here for you as a powerbit.
function runas {
param(
[Parameter(Mandatory=$true,Position=0)]
[string]$FilePath,
[Parameter(Mandatory=$false,Position=1)]
[string] $ArgumentList
)
if ($ArgumentList) {
start -Verb runas -FilePath $FilePath -ArgumentList $ArgumentList
} else {
start -Verb runas $FilePath
}
}
Add this to your profile and you can use it like this:
runas notepad c:\windows\system32\drivers\etc
Feel free to change the name from runas if you don’t like that name. For some, the name is probably confusing if you were used to using runas from a command prompt. I’m used to typing ‘start -verb runas’ so it makes sense for me.
This past weekend I finished my chapter on Group Policy for the PowerShell Bible. One of my coauthors asked me if I was going to include a script that configures WinRM (PowerShell remoting) via group policy in my chapter. Truth be told, I hadn’t thought of it, but I love a challenge!
Unfortunately, when all was said and done the script that I wrote was a bit overly wordy and dug deeply into concepts that were out of scope for the 12 page chapter I was writing on the GroupPolicy module that ships with the Group Policy Management Console (GPMC) in 2k8R2 and RSAT. Except for a few minor quirks like using ‘Yes’ and ‘No’ for parameter values instead of using $true and $false, the GroupPolicy module is a really great set of cmdlets because of what you can do with it. You can create GPO reports, RSOPs, manage links, manage security, adjust inheritance, and backup and restore extremely easily (feel free to preorder the book to see just how easy
).
The final bit that makes this module amazing is that you can dynamically manipulate the GPO settings themselves as long as they are either ADMX/ADML registry changes or the relatively new 2008 registry settings under preferences. Actually, you don’t even need an ADMX/ADML with a registry specified to create an ad-hoc registry change within a policy via the cmdlets (mind you this screws up your normal GPMC view when you do so – they look like orphaned settings like you would see when someone accidentally deletes an admx from your system). The problem with the cmdlets that let you modify and work with these registry settings is that they are completely disconnected from the ADMX/ADMLs. In other words you must specify the registry key, name, and value you want the policy to change rather than the name of the setting you are looking to change that is shown in the ADML and the GPMC – names like “Allow automatic configuration of listners”. The only way you can get these registry keys and possible values is to manually crack open the ADMX/ADML files to see what each setting is touching. This means you need to do a lot of detective work in order to script changes to a GPO.
Enabling WinRM via group policy is pretty decently documented on many blogs out there on the Internet. It requires you to touch three places: the WinRM settings, the firewall, and the place where you configure services to start up automatically. The WinRM settings were easy to track down because it has an ADMX and ADML file. I was able to crack them open to find that the policy makes changes to this key: HKLM:\Software\Policies\Microsoft\Windows\WinRM\Service. The firewall setting was a bit trickier because there is no direct ADMX and ADML file, but I saw that the following key was created after the GPO was applied to my computer: HKLM:\Software\Policies\Microsoft\WindowsFirewall\FirewallRules. The name and value you need to set are both long and undocumented (as far as I can tell), but they make perfect sense. The final bit was figuring out how to start the service. This wound up being ridiculously tricky. After a lot of tinkering I learned that service startup and security information is stored in a flat file in sysvol called GptTmpl.inf underneath the GUID for the policy. In the end the script really speaks for itself.
I am dying to have someone else try this script out to see if everything works perfectly on another 2k8R2 domain. It’s possible that I have something tied directly to my domain (other than the OU at the beginning), but I’m not sure. I’m concerned that the firewall settings need LDAP objects to be created or updated. Please let me know in the comments if you get it to work or have any problems.
Without further ado, todo, and blahdoo, I present a script to generate a GPO to enable WinRM in your domain that will be bound to an OU you specify in $OU (yes I’m too lazy to param()).
Import-Module GroupPolicy
# Specify the OU to link the GPO to
$OU = 'OU=TheIsland,DC=home,DC=toenuff,DC=com'
# Create the GPO
$gpo = New-GPO Remoting -Comment 'GPO that will enable remoting'
# Add the policy to allow WinRM
$winrmkey = 'HKLM\Software\Policies\Microsoft\Windows\WinRM\Service'
$params = @{
Key = $winrmkey;
ValueName = 'AllowAutoConfig';
Value = 1;
Type = 'Dword';
}
$gpo |Set-GPRegistryValue @params
# Set the filters to allow IPv4 and IPv6 traffic from all IPs for WinRM
$winrmkey = 'HKLM\Software\Policies\Microsoft\Windows\WinRM\Service'
$params = @{
Key = $winrmkey;
ValueName = 'IPv4Filter';
Value = '*';
Type = 'String';
}
$gpo |Set-GPRegistryValue @params
$params.ValueName = 'IPv6Filter'
$gpo |Set-GPRegistryValue @params
# Add the firewall rule to allow port 5985 for WinRM HTTP traffic
$fwrule = 'v2.10|Action=Allow|Active=TRUE|Dir=In|Protocol=6|LPort=5985|'
'App=System|Name=@FirewallAPI.dll,-30253|Desc=@FirewallAPI.dll'
$fwrule += ',-30256|EmbedCtxt=@FirewallAPI.dll,-30252'
$params = @{
Key = 'HKLM\Software\Policies\Microsoft\WindowsFirewall\FirewallRules';
ValueName = 'WINRM-HTTP-In-TCP';
Value = $fwrule;
Type = 'String';
}
$gpo |Set-GPRegistryValue @params
# Manually add the inf setting to configure WinRM to start automatically
$inf = @'
[Unicode]
Unicode=yes
[Version]
signature="$CHICAGO$"
Revision=1
[Service General Setting]
"WinRM",2,"D:AR"
'@
$sdsad = [System.DirectoryServices.ActiveDirectory.Domain]
$domain = $sdsad::GetCurrentDomain().name
$path = "\\$domain\sysvol\$($env:LOGONSERVER)\Policies\$($gpo.Id)\Machine\"
$path += "Microsoft\Windows NT\SecEdit"
if (!(Test-Path $path)) {
md $path
}
$inf |Out-File (Join-Path $path 'GptTmpl.inf')
# Link the GPO to the OU
$link = $gpo |
New-GPLink -Target $OU -LinkEnabled 'Yes'
While I do have a Win 7 Pro license, pure laziness has kept me from installing it on my Alienware laptop. This is fine for most things, but I ran into a bit of a problem while writing the Active Directory chapter for the PowerShell Bible. In order to use the ActiveDirectory module via remoting on my 2k8r2 server I needed to use CredSSP as my authentication type. Step one was easy. Launch PowerShell as an admin and run:
Enable-WSManCredSSP -Role client -DelegateComputer server1.home.toenuff.com
Now, if you’ve ever run this before you are probably familiar with the next error message that will return if you try and run Enter-PSSession or Invoke-Command with -Authentication CredSSP:
Enter-PSSession : Connecting to remote server failed with the following error message : The WinRM client cannot process the request. A computer policy does not allow the delegation of the user credentials to the target computer. Use gpedit.msc and look at the following policy : Computer Configuration -> Administrative Templates -> System -> Credentials Delegation -> Allow Delegating Fresh Credentials. Verify that it is enabled and configured with an SPN ap propriate for the target computer. For example, for a target computer name "myserver.domain. com", the SPN can be one of the following: WSMAN/myserver.domain.com or WSMAN/*.domain.com. For more information, see the about_Remote_Troubleshooting Help topic. At line:1 char:16 + Enter-PSSession <<<< -Credential $cred server1 -Authentication credssp + CategoryInfo : InvalidArgument: (server1:String) [Enter-PSSession], PSRemoti ngTransportException + FullyQualifiedErrorId : CreateRemoteRunspaceFailed
In most versions of Windows you can then follow the instructions in the error message which tell you explicitly how to handle this, but with a home version of Windows this is a bit of a problem because there is no gpedit.msc snapin or local policy to modify. Fortunately, we know that every policy is really just a registry setting. I was able to track it down specifically:
$allowed = @('WSMAN/*.home.toenuff.com','WSMAN/server1') $key = 'hklm:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation' if (!(Test-Path $key)) { md $key } New-ItemProperty -Path $key -Name AllowFreshCredentials -Value 1 -PropertyType Dword -Force $key = Join-Path $key 'AllowFreshCredentials' if (!(Test-Path $key)) { md $key } $i = 1 $allowed |% { # Script does not take into account existing entries in this key New-ItemProperty -Path $key -Name $i -Value $_ -PropertyType String -Force $i++ }