Category Archives: PowerShell

Be God

If you want to feel like God in your own Windows 8 universe, try this little powerShell one-liner:

New-Item -ItemType Directory -Path "$env:USERPROFILE\Desktop\GodMode.{ED7BA470-8E54-465E-825C-99712043E01C}"

This will add an ikon to your desktop similar to this one

God mode

God mode

In that folder you will find a collection of most Windows 8 settings. So now you can act like God in your Windows 8 universe.

PowerShell loves enumerations

One of the things that make PowerShell oh-so-great is its tight integration with .NET Framework. As a simple example, in the framework there are many pre-define values, often stored as enumerated types. Enums are great because they allow us to define a set of values and then let the user (or program) choose among these values.

Another great thing with PowerShell is that it makes command arguments ‘pickable’ on the command line. So if I’m running a command and I am unsure of which arguments can be used I can simply press tab and I will se the first valid parameter value.
Let me show you the simple beauty of Enums together with PowerShell scripts.

function Get-SpecialFolderPath
{
  param ( [System.Environment+SpecialFolder]$SpecialFolder )
  return [System.Environment]::GetFolderPath($SpecialFolder)
}

This function takes one argument, the alias of a special folder, and returns the physical location of the special folder. The special folders that Windows knows about are define in the enumeration Environment.SpecialFolder. You can use the function like this:

Get-SpecialFolderPath -SpecialFolder Cookies
C:\Users\Joakim\AppData\Local\Microsoft\Windows\INetCookies

This in itself may not impress you (me neither:-)). But when you use this function toghether with your own function or other PowerShell cmdlets it becomes a great help for the user. Let’s say you want to quickly check what is in the users Cookie folder. How would you know where the cookies are stored? With this function you don’t, it is enough to type:

Get-SpecialFolderPath *tab*

As this is a static blogpost I can’t show you what happens when I press the <tab> key. but what does happen is that you will get the first value in the SpecialFolder enumeration, “Admintools”. Press tab again and you’ll get the second value which is “ApplicationData”. Another press of the tab key gies you “CDBurning” and so on.  You can of course avoid pressing tab many times by providing part of the name of the folder your are looking for:

Get-SpecialFolderPath coo *tab*

When you press tab this will expand to:

Get-SpecialFolderPath Cookies

A more relevant example: If you want to list all items on the users desktop you can combine Get-ChildItem with Get-SpecialFolder as this:

Get-ChildItem (Get-SpecialFolderPath Desktop)

This will give you a listing of all items in your dekstop folder. Again, the beauty is that you do not need to know the exact path to the Desktop folder.

Using enumerations to get input can really make your PowerShell scripts a lot easier to use and safer. So I hope you take some time to play around with using enumerations with your functions and cmdlets!

$env:HOME doesn’t work in PowerShell $PROFILE

Today I wanted to setup my PowerShell $PROFILE to make it easier to work with all the modules I learned about at the PowerShell Summit. I wanted to add an additional path to the environment variable $PSModulePath. Something that should be a picece of cake.

I store additional modules in the folder ‘Documents\WindowsPowerShell\Modules’ under my userdirectory (C:\Users\Joakim). So simply joining the path using Join-Path and add the result to $ENV:PSModulePath should do the trick:

$env:PSModulePath += ';'+ (Join-Path -Path ${env:HOME} -ChildPath 'Documents\WindowsPowerShell\Modules')

Unfortunately that didn’t work. And it confused me. Executing this on the PowerShell commandline worked fine, but when I put the line above in my $PROFILE it gave me this error:

Join-Path : Cannot bind argument to parameter 'Path' because it is null.
At C:\Users\Joakim\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1:3 char:44
+ $env:PSModulePath += ';'+ (Join-Path -Path ${env:HOME} -ChildPath 'Do ...
+ ~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Join-Path], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.JoinPathCommand

I understand what the error says and apparently the environment variable HOME is not instantiated when the $PROFILE is executed. This really confuses me. I already have the following line in my profile and it workes like a charm:

[System.Environment]::SetEnvironmentVariable('PATH',"C:\Users\Joakim\SkyDrive\Util;$env:PATH")

So environment variables are available when $PROFILE is executing… After a bit of frustration I changed from using

$env:HOME

to using

$env:USERPROFILE

and then it works!

So a word of advise if you want to find the users homedirectory when in the context of $PROFILE. Do not use $env:HOME

If anyone can explan when the HOME variable is instatiated vs the USERPROFILE… I’m listening 😉

Basic inventory of HyperV virtual machines using PowerShell

Working at large scale with thousands of servers customers often asks for a list of machines with various properties for each machine.

Most of the time the customer want this information in an simple format (read CSV, the World isn’t as advanced as you like!) so that they can use it internally. In this blogpost I will show how you can get the information about memory, CPU count etc for a set of Hyper-V machines from Virtual Machine Manager via PowerShell.

Start a PowerShell command line and load the PowerShell Snap-In for Virtual Machine Manager.

Add-PSSnapin -Name Microsoft.SystemCenter.VirtualMachineManager

Now we can work with the commands made available to us by the Snap-In, if you want to find all the commands that are available issue:

Get-Command -Module Microsoft.SystemCenter.VirtualMachineManager

So let’s begin by loading information about all our machines from the VMM host into a variable named $VMs

$VMs = Get-VM -VMMServer hyperv-vmm01.sth.basefarm.net

What the above command does is to load all of the VMs on the host HYPER-V-01.mydomain.com into the variable $VMs. This means we will only do one call to the server which avoid generating unnecessary load.

Now let’s check how many machines we have:

$VMs.Count

And now that we know we have machines to query, let’s find out what attributes exists (things we can get into our output)

$VMs | Get-Member -MemberType Property

For example, to find all macines that are powered off:

 $VMs | where { $_.Status -eq 'PowerOff' } | select VMHost, name , Memory, CPUCount , Status

The above example adds some complexity to the command, but it is to filter so we only see machines that have the status is ‘PowerOff’.

Now let’s get what we wanted from the beginning, a list of machines for a specific customer. The list should include name of the VM host, VM name, memory, number of CPUs and current status.

 $VMs | where { $_.Name -Match 'CUST*' } | select VMHost, name , Memory, CPUCount , Status

This will list all machines who’s name begins with ‘CUST’. So we now have found what we wanted!

But instead of copying & pasting this we want to write the result to a CSV file so we can send that to the customer. Let’s make that easier by getting the output of the above command into a variable named $result

 $result = $VMs | where { $_.Name -Match 'LFO*' } | select VMHost, name , Memory, CPUCount , Status

Now our ‘report’ is stored in the $result variable and we can use standard PowerShell to export it to a CSV file:

$result | Export-Csv -NoTypeInformation -Delimiter ';' .\report.csv

Now our report is available in a CSV file on the file ‘report.csv’ (in the current directory)

A very basic way of getting your Hyper-V inventory out!

Quick way to name your NICs in Windows Servers

If you, like me, manage many servers, it’s essential to name network adapters in a way that makes it easy to troubleshoot issues when they arise.

In complex networks with thousands of servers and all servers connected using multiple paths a consistent naming standard is very important!

PowerShell and the cmdlets available in Windows Server makes naming adapters a breeze. The servers we usualy deploy have built in four (4) port network adapters. We like to name the Windows NICs the same as is the default in Linux; eth0, eth1, etc.

In the following example we name the adapters eth0, eth1, eth2 and eth3 in Windows. The NIC with the lowest MAC address gets the name eth0 etc. (If you prefer to to start naming adapters from eth1 change the variable $NICs to 0):

 $NICs = -1
 Get-NetAdapter Etherne* | Sort-Object MacAddress | % { Rename-NetAdapter -InterfaceAlias $_.InterfaceAlias -NewName eth$NICs }

PowerShell really makes life easy 😉

Default = PowerShell

In a earlier blog post I wrote about how to generate passwords using PowerShell. Here comes another PowerShell advice for you.

Now that Windows Server 2012 will be officially available many servers will be installed as ‘core’ servers. That is in itself a very good thing. The bad thing about it is that Microsoft have set the default command Shell to be CMD.EXE. Nothing wrong with that per se but these days administrators should go PowerShell all the way. If you’re like me and want PowerShell to be your default shell even in core servers, do this to make PowerShell your default shell:

$Path = 'Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\winlogon'
 Set-ItemProperty -Confirm -Path $Path -Name Shell -Value 'PowerShell.exe -noExit -Command Set-Location "$env:userprofile"

The next time you login to the machine you will get PowerShell as the default shell 🙂

Generate passwords using PowerShell

The other day I needed to generate some 1400+ new user passwords. Being a lazy person I figured that PowerShell could rescue me. This is what I did to check that my idea worked:

PS C:\> Add-Type -AssemblyName "System.Web"
 PS C:\> [System.Web.Security.Membership]::GeneratePassword(10,2)
 35&OjFtM^k

As you can see this generates a password that is 10 characters in length and contains at least 2 non-alphanumeric characters. Now all I needed was to iterate this 1400 times and then output the result to the clipboard, simple as pie:

PS C:\> 1..1400 | % { [System.Web.Security.Membership]::GeneratePassword(10,2) } | clip

And that is a 1400 new passwords stored in the clipboard. I can now paste these or pipe them into a set password routine.