Here are some of the scripts that I used during the demonstration in VA Beach.

Profiles:

Example #1

[ps]
function prompt
{
"Xenophane " + $(get-location) + ">"
}
[/ps]

Example #2

[ps]
function prompt
{
"Processes " + (Get-Process).Count+ " " + $(get-location) + "> "
}
[/ps]

Example #3 (Example taken from website)

[ps]
function Prompt
{
$id = 1
$historyItem = Get-History -Count 1
if($historyItem)
{
$id = $historyItem.Id + 1
}

Write-Host -ForegroundColor DarkGray n[$(Get-Location)]
Write-Host -NoNewLine PS$id
$host.UI.RawUI.WindowTitle = $(Get-Location)

b
}
[/ps]

Example #4 (Overdone one)

[ps]
function prompt
{
[wmi]$Global:Cdrive=Get-WmiObject -query "Select * from win32_logicaldisk where deviceid=’c:’"
#Define Cdrive as global variable, which is type cast as a wmi
$processcount=(Get-Process).Count
#Define variable processcount as number of processes running
$cpuload=(Get-WmiObject win32_processor).loadpercentage
#cpuload is defined as a variable
$diskinfoC=" Free C: "+"{0:N2}" -f (($global:Cdrive.freespace/1gb)/($global:cdrive.size/1gb)*100)+"%"
#diskinfoC is defined, {0:N2} is .NET for 2 decimal places, -f is a the "format" property of the string object.
# Then the amount of free space on drive C is divided by the size of drive C multiplies by 100 to get
#the percentage of free space.
$time=Get-WmiObject -class Win32_OperatingSystem
#Define $time is object Win32_OperatingSystem
$t=$time.ConvertToDateTime($time.Lastbootuptime)
#Define #t as the result of the convertion of LastBootuptime into a readable dateTime format.
[TimeSpan]$uptime=New-TimeSpan $t $(get-date)
#Typecast the variable $uptime as a [timespan], the timespan cmdlet in powershell is a way to do date arithmetic in ps
#This way we can compare our variable $t (Which was Lastbootuptime) and the current time Get-date cmdlet
$up="$($uptime.days)d $($uptime.hours)h $($uptime.minutes)m $($uptime.seconds)s"
#define variable $up to display the uptime in days/hours/minuted/seconds
$TextToDisplay="CPU:"+$cpuload+"% Processes:" + $processcount + $diskinfoC+ " " + $diskinfoG+ " "+ ([char]0x25b2)+$up +" "+(Get-Date -format g)
#define one variable that contains all the data we collected so far.
Write-Host -fore red $TextToDisplay
#Write the information to the screen in red
Write-Host "My PoSh:" $(get-location) -nonewline
#Display the regular prompt.
}

[/ps]

I got back from Virgina Beach this past Saturday, after attending a very good conference, where I learned a lot of new an exciting stuff… And of course it was very good to meet up with the “gang” again.

This year I did a presentation on Powershell (wow 1 hour and 20 min goes past fast, when you are having fun)
As the presenter rookie I am, I was not able to time my presentation, so when time was up, even went 10 min over time, I still missed about a third of the presentation. So to make up for that, I will post all the scripts and the prensentation in its entirety, so hope you will find it usefull.

Seems as if Quest has been doing some really cool things with Powershell,  from what I can read, they have “rolled” it up as a webservice, meaning that you can now run your Powershell scripts over HTTPS from either you local machine, your phone,  anything that supports a newer web browser.

From what I can gather from the manual, you install it on a server running IIS, you set up the site, security etc. Then you can connect to the site from a webbrowser, and you will get a PowerShell commandline in your browser.  Combined with Powershell v.2’s remoting features this has the potential of becoming an awesome tool. One of the nice features is that you can save “favourites” in your web sessions,  here favourites should be seen as snippets of Powershell code, that you can just click on the run.

So imagine, you have a Powershell script that runs and checks if a particular service is running, if not it does “Something”. You  are sitting by the pool drinking a nice cold beer, when you get a call that there is trouble in the office. You pick up you android phone, open up a browser connects to www.whereIWork.com/MyPowerShell, login.. click your Powershell favourite/snippet, and your are done..

If you figure out that did not solve the problem, you just do

Enter-PsSession -Computername <Problematic Servername>, you are now running a Powershell session on the remote server, where you can look around the system, and try to fix the problem, as if you were sitting in front the server, with a Powershell console open.

Can’t wait to I can find some time to get it tested, even thoug it still is in Beta.

There has been some speculation on the web regarding the ADMGS for Server 2008 and 2003, if it would be possible to use it, in an environment without at least one Server 2008 R2.

So I decided to test it, I built a Server 2003 Domain, comprised of a single 2003 R2 Domain Controller, and 1 Windows 7 Enterprise workstation.
I installed Server 2003 into a VM, installed all updates inlcuding SP2, I then ran DCpromo to setup the new domain. When that was complete I downloaded the 2 required patches for 2003, to be able to run ADMGS.
(NDP35SP1-KB969166-x86.exe and 376193_ENU_i386_zip.exe), where the last of the two patches requires registration to download.

When they were installed, I downloaded the ADMGS setup file (Windows5.2-KB968934-x86.exe).
I created a few users, and everything worked fine.

I then built a Windows 7 client, downloaded the RSAT for Win 7 and joined it to the domain. I then ran my Powershell script to enable all RSAT tools on the machine.

The first thing I tried out was the new Active Directory Administrative Center, the new AD manament GUI built on Powershell, it connected to the DC, and I searched for the users I had created, and they showed up **SUCCESS**
I played around with it some more, creating/deleting some users, and everything seemed to work fine, so I tried out the “Active Directory Module for PowerShell”, pulling down some information about users and computers which also worked.

So all in all it seems as if it is not required to have a Server 2008 R2 in you domain/forest in order to use ADWS (Active Directory Web services) in your domain.

So there you have it folks, there are now a full live competitor to the Quest AD cmdlets, which have been around for a while and have let you manage you 2003 AD… Let the fight begin 🙂

Yesterday I was doing some maintenance on a machine at work, and when I looked in device manager, i saw that it was a Hyper-V guest machine, and I asked a few colleagues about it, because I was pretty sure that we didn’t have any machines running Hyper-V.. So I needed to find out which machine, so I wrote a quick and dirty PowerShell script to find it.

First off I knew that it had to be a Windows 2008 machine, that boiled down the possible machines quite a lot.

Here is what I did
[ps]
Get-QADComputer | Where {$_.OSname -match "2008"} | % { Get-Service -ComputerName $_.Name} | where {$_.Displayname -match "hyper"} | select Machinename, Displayname
[/ps]

I get all computers that are Windows server 2008, and for each server 2008, I look for services containing the word “hyper”.
This is not a very efficient search, but a quick and dirty way to find the info that I needed.

—-EDIT—–

Kirk Munro pointed out to me that Hyper-V actually registers a SCP (Service Connection Point) in AD, so instead of querying all the machines, you can just query the list of SCP’s in AD instead, which is much more efficient.

[ps]
Get-QADObject -Name ‘Microsoft Hyper-V’ -Type serviceConnectionPoint | Get-QADComputer -Identity {$_.ParentContainerDN}
[/ps]

I have just upgraded my machines to Windows 7 RTM, before I did the reinstall I did full backup of my old Vista machines, of course I figured out that I had not gotten all the files out of the Vista machines before I upgraded, So I had to restore some files from the resulting .vhd backup images. But when I started Windows 7 restore, it did not recognize the backup folders.. So I thought I would just mount the vhd backup files manually, by going into Computer Management -> Disk management. But after having done that a few times, I thought it was too much hassle, so I decided to write a little PowerShell script to mount the vhd files for me.
[ps]
# PowerShell function to create a script file for diskpart
# and the execute diskpart with the scriptfile
function Mount-Vhd {param([String]$InputFile)
"SELECT VDISK FILE=""$InputFile""" + "rn" + "ATTACH VDISK" | Out-File $env:TEMP\Mountvhd.txt -Encoding "ASCII"
Invoke-Expression -Command "Diskpart.exe /s $env:TEMP\Mountvhd.txt"
}
Mount-Vhd $args[0]
[/ps]
The above script has to be saved as “Mount-vhd.ps1″

But I wanted something even more simple, I just wanted to be able to right-click a .vhd file and choose open, so I created this little .reg file, that will allow you to right click a .vhd file and choose open.

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\.vhd]

[HKEY_CLASSES_ROOT\.vhd\shell]
@=”Open VHD”

[HKEY_CLASSES_ROOT\.vhd\shell\Open VHD]
@=”Open &VHD”

[HKEY_CLASSES_ROOT\.vhd\shell\Open VHD\command]
@=hex(2):22,00,43,00,3a,00,5c,00,57,00,69,00,6e,00,64,00,6f,00,77,00,73,00,5c,\
00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,57,00,69,00,6e,00,\
64,00,6f,00,77,00,73,00,50,00,6f,00,77,00,65,00,72,00,53,00,68,00,65,00,6c,\
00,6c,00,5c,00,76,00,31,00,2e,00,30,00,5c,00,70,00,6f,00,77,00,65,00,72,00,\
73,00,68,00,65,00,6c,00,6c,00,2e,00,65,00,78,00,65,00,22,00,20,00,2d,00,57,\
00,69,00,6e,00,64,00,6f,00,77,00,53,00,74,00,79,00,6c,00,65,00,20,00,68,00,\
69,00,64,00,64,00,65,00,6e,00,20,00,2d,00,66,00,69,00,6c,00,65,00,20,00,22,\
00,63,00,3a,00,5c,00,74,00,6f,00,6f,00,6c,00,73,00,5c,00,4d,00,6f,00,75,00,\
6e,00,74,00,2d,00,76,00,68,00,64,00,2e,00,70,00,73,00,31,00,22,00,20,00,22,\
00,25,00,31,00,22,00,00,00

When you import the file, all the hex values are converted back to ascii chars, which you can see under [HKEY_CLASSES_ROOT\.vhd\shell\Open VHD\command] of course

Here is what will be written:

“C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe” -WindowStyle hidden -file “c:\tools\Mount-vhd.ps1” “%1”

As you can see it expects the Mount-Vhd powershell file to be located in C:\tools\ in order to work. I have so far not been able to make it work, without referencing the file directly.

But when you have imported the .reg file, you can just navigate to [HKEY_CLASSES_ROOT\.vhd\shell\Open VHD\command] and change the path to anything you like.

You can download both files from here: http://xipher.dk/Tools/ImportVHDsettings.zip

You can now get PowerShell v2 as a download for Windows Vista and Windows Server 2008 from Microsoft Connect.

Windows XP and Windows Server 2003 SP2 are not included in this RC release but they will be made available in future.

For more information, and download link, see the PowerShell team blog announcement.

http://blogs.msdn.com/powershell/archive/2009/08/14/powershell-2-0-for-windows-vista-and-windows-server-2008-release-candidate.aspx

At work we have a spreadsheet, where we keep track of our mobile phones, and 3G dongles, in it we keep info about the IMEI code, PUK/PIN codes etc.

Today we found a few SIM cards lying around, the only thing on them was the SIM card number (19 digits). When I went to compare that to the info in the file, I realised that that was not noted in the file, so I had no way to match the SIM with a Phone number, PIN/PUK code.

So I called the telco, they were willing/able to supply me with an csv file containing the phone number, SIM card number, and PUK code.

So I took on the task to update our document, and check that the info in our original document was correct, but doing this for 45+ subscriptions, I thought I would write a script, and what better language than PowerShell.

Here is what I ended up with.

The CSV file contains 3 headers
MSISDN1,UICCID,PUK1

[ps]

#Location of the Excel file I want to edit
$FileLoc = "C:\temp\test.xls"
#Create Excel Com Object, and display it
$excel = new-object -com Excel.Application
$excel.visible = $true

#Open Workbook,
$workbooks = $excel.workbooks.Open($FileLoc)
$worksheets = $workbooks.Worksheets
$worksheet = $worksheets.Item(1)
#Select the range we want to look at
#In this example, I am only checking within one Column
$range = $worksheet.Range("M3", "M150")
#Load CSV file
$PhoneInfo = Import-Csv c:\Temp\TlfPUK.csv
#Run through the colums
foreach($col in $range.Columns){
foreach($row in $col.Rows){
Foreach ($Phone in $PhoneInfo){
#In the CSV file, MSISDN1 represents the phone number, but with the international dial code in front
#that is why I use substring to get the last 8 chars and compare it the value of the current cell.
#If the phone numbers match, do something
If ( $Phone.MSISDN1.substring($Phone.MSISDN1.length -8,8) -eq $row.Text) {
#The two colums what will contain the data is set, this is just 4 & 5 columns to the right of the column that contains the phone number
$ColIMEI = $row.Column + 5
$ColPUK = $row.Column + 4
#Here I fill in the SIMCard number (UICCID) and PUK code
$worksheet.Cells.Item($row.Row, $ColIMEI) = $Phone.UICCID
$worksheet.Cells.Item($row.Row, $ColPUK) = $Phone.PUK1
#$Phone.UICCID
}
}

}

}

[/ps]

A while back I created a small AutoIt script, to prevent the screensaver from kicking in, last employer had screensaver kick after 5 min, which was rather annoying when you are out doing presentations, and you have to punch in your password everytime the screensaver kicks in..

Then I read a post from Dimitry Sotnikov that he had written a small PowerShell script to do something similar, and figured out that he uses Wshell to send a keystroke, I thought that could be annoying, if you start working on the computer, and forget to stop the execution of the script, and it suddenly types a character.
So I decided to figure out how to move the mouse from PowerShell, l assumed that I would have to do it using a .Net class, after looking around MSDN I found

[System.Windows.Forms.Cursor]

So combining that with Dimitry’s script we get:
[ps]

param($minutes = 60)

for ($i = 0; $i -lt $minutes; $i++) {
Start-Sleep -Seconds 60
$Pos = [System.Windows.Forms.Cursor]::Position
[System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point((($Pos.X) + 1) , $Pos.Y)

}
[/ps]

The other day I was tasked with creating a spreadsheet containing a list of all servers in our network, manager wanted a “sheet” for each computer, and an “index” sheet with links to all the other sheets.

Since we have more than 150 servers, there was no way I was going to create this list by hand… So I wrote a quick and dirty little Powershell function.

[sourcecode lang=”PosH”]

Function Fill-Excel {
BEGIN {
$xl = new-object -comobject excel.application
$xl.Visible = $true
#I specify an existing filename, since creating the link in Excel requires a filename
$wb = $xl.Workbooks.Open(“C:\Temp\test.xlsx”)
$ws = $wb.Worksheets.Item(1)
$xl.ActiveSheet.Name = “List”
$row = 1
}

Process {
$_
$q = $_
$z = $q.ToUpper()
$xl.Sheets.Add()
$xl.ActiveSheet.Name = $z
$wh = $xl.ActiveSheet
$wh.Cells.Item(1,1) = “=HYPERLINK("[test.xlsx]List!A1“;"Back To List“)”
$ws.Cells.Item($row,1) = “=HYPERLINK("[test.xlsx]$z!A1“;"$z“)”
$row++
}
}

$s= “Computer1″,”CompPUTER2″,”comPUTer3”
$s | Fill-Excel
[/sourcecode]

This will open the xslx filed called test.xlsx under c:\temp and create an index sheet called “list”, and a sheet for each object that is passed to the function, it also creates a Link in A1 that refers back to the index sheet. On the Index sheet a link to each new sheet is created.

In the above example I “manually” pipe in some text string, but it could also be something like this:

[sourcecode lang=”PosH”]
#
#
$s = Get-QADComputer | Where {$_.OSname -match “Server”} | select name
[/sourcecode]

So since it is a function, you can pass virtually any string to it, and it will populate the excel sheet for you.