Monthly Archives: June 2011

Force user to change password

I’ve always liked scripting against Active Directory as it has one of the potentially richest environments fro automation.  Normally I use the Quest or Microsoft cmdlets but every now and then its fun to back to using ADSI.

I came a cross this problem:

How do I get a user name and then force the user to change their password at next logon.

$user = Read-Host "Input user name"            
            
$dom = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()            
$root = $dom.GetDirectoryEntry()            
            
$search = [System.DirectoryServices.DirectorySearcher]$root            
$search.Filter = "(&(objectclass=user)(objectcategory=user)(Name=$user))"            
$search.SizeLimit = 3000            
$result = $search.FindOne()            
            
$target = $result.GetDirectoryEntry()            
$target.Put("pwdLastSet",0)            
$target.SetInfo()


Use read-host to get the user name. Perform a directory search for the name. Get a directory object for the user and then set pwdLastSet = 0

Modifying favourites

if we use our get-favourite function to look at the content of favourite files

 

get-favourite | select -f 5 | foreach{""; get-content -Path $_.path}

 

we see this sort of structure

[DEFAULT]
BASEURL=http://www.bing.com/
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
[InternetShortcut]
URL=http://www.bing.com/
IDList=
IconFile=http://www.bing.com/favicon.ico
IconIndex=1

 

Not all files have the BASEURL or [DEFAULT] section but they do have the [InternetShortcut]. The other bit we need to consider is the iconfile

We can put together a function to change the URL in a favourite

function set-favourite{             
[CmdletBinding()]             
param(            
[parameter(Mandatory=$true,            
   ValueFromPipeline=$true,             
   ValueFromPipelineByPropertyName=$true)]            
[ValidateNotNullOrEmpty()]            
[string]$path,            
            
[ValidateNotNullOrEmpty()]            
[string]$url            
)            
BEGIN{}#begin             
PROCESS{            
$lines = Get-Content -Path $path            
            
$i = 0            
foreach($line in $lines) {            
             
 if ($line.StartsWith("BASEURL") ){$lines[$i] = "BASEURL=$url"}            
 if ($line.StartsWith("URL") ){$lines[$i] = "URL=$url"}            
 if ($line.StartsWith("IconFile") ){$lines[$i] = "IconFile=$url/favicon.ico"}            
 $i++             
}            
            
Set-Content -Value $lines -Path $path            
            
}#process             
END{}#end            
            
<# 
.SYNOPSIS
Changes URL of a favourite

.DESCRIPTION
Changes URL of a favourite


.EXAMPLE
get-favourite | where {$_.Name -like "google"} | set-favourite -url "www.bing.com"

#>            
            
}


The function can be used as follows



get-favourite | where {$_.Name -like "google"} | set-favourite -url www.bing.com



 



Next job is to create a favourite from scratch

Networking pains

Last week my wireless router decided that it had enough and wasn’t going to work any more. This was annoying because I was due to give a user group presentation that night.

I got a new router up and working but today discovered that connectivity from my Hyper-V environment wasn’t working. With the previous router I’d configured bridging between a Hyper-V virtual network and the wireless adapter in my host. That had to be recreated at which point I discovered that the new router didn’t want to support bridging.

I ended up using RRAS and NAT to get the connectivity. The instructions I found here

http://sqlblog.com/blogs/john_paul_cook/archive/2008/03/23/using-wireless-with-hyper-v.aspx

provide most of what you need.

Remember to set the default gateways and DNS servers properly for it all to work.

Monitor brightness–or not

In this post

http://msmvps.com/blogs/richardsiddaway/archive/2011/06/26/1795135.aspx?CommentPosted=true#commentmessage

I discussed using WMI to check the monitor’s brightness.  Further investigation has shown that not all monitors support the interface to WMI so it is a bit of trial and error to check if it does work on your machine

Tidying up the favourites list

I recently showed how to generate a list of the favourites recorded on your system

http://msmvps.com/blogs/richardsiddaway/archive/2011/06/24/viewing-favourites.aspx

If like me you want to tidy these up from time to time it would be good not to have to search through all of them to perform the deletions using the GUI

Lets turn our previous script into an advanced function

function get-favourite{             
[CmdletBinding()]             
param()            
BEGIN{}#begin             
PROCESS{            
$favs = New-Object -ComObject Shell.Application            
Get-ChildItem -Path $favs.NameSpace(0x6).Self.Path -Recurse |            
where {-not $_.PSIsContainer} |            
foreach {            
 $fav = New-Object -TypeName PSObject -Property @{            
  Name = $_.BaseName            
  Path = $_.FullName            
 }            
             
 Get-Content -Path $_.FullName | foreach {            
  if ($_.StartsWith("URL=")) {            
   $fav | Add-Member -MemberType NoteProperty -Name URL -Value $_.Replace("URL=","")}            
 }            
 $fav.PSTypeNames[0] = "Favourite"             
 $fav            
}            
            
}#process             
END{}#end            
            
<# 
.SYNOPSIS
Lists defined favourites

.DESCRIPTION
Lists favourites defined in Internet Explorer


.EXAMPLE
get-favourite

.EXAMPLE
get-favourite | where {$_.Name -like "re*"}  

.EXAMPLE
get-favourite | where {$_.Name -like "ree*"} | Remove-Item   

#>            
            
}


A few simple changes give us the required code. I’ve added the full name of the favourite as a path property. This means I can pipe straight into remove-item as shown in the third example.



I’ve also reset the output object type because I want to create a format file for this so that the path isn’t displayed by default. I will add some functions to modify and create favourites as well.

Windows Updates: remote machines

 

My main blog is now at http://msmvps.com/blogs/RichardSiddaway/Default.aspx but I also maintain http://richardspowershellblog.wordpress.com/ as a mirror and in case I want the two to diverge at some point.

My recent posts on accessing Windows updates – especially when testing for available updates have raised a number of comments

http://msmvps.com/blogs/richardsiddaway/archive/2011/06/12/windows-updates-4-tidy-up-get-update.aspx

http://richardspowershellblog.wordpress.com/2011/06/12/windows-updates-4-tidy-up-get-update/

One very interesting question is about getting information on the state of updates on remote machines.

We are using COM classes in these functions. It is possible for programmers to access COM objects on remote machines but it isn’t an easy proposition in PowerShell. The best way round this I can think of is to do something like this

get-qadcomputer |
foreach {
invoke-command -filepath c:\scripts\getupdates.ps1 -ComputerName $_.Name

}

The getupdates script would contain this code

$session = New-Object -ComObject Microsoft.Update.Session            
$searcher = $session.CreateUpdateSearcher()            
            
$result = $searcher.Search("IsInstalled=0 and Type='Software' and ISHidden=0" )            
            
if ($result.Updates.Count -gt 0){            
 $result.Updates |             
 select Title, IsHidden, IsDownloaded, IsMandatory,             
 IsUninstallable, RebootRequired, Description            
}            
else {            
 Write-Host " No updates available"            
}


Alternatively leave it as a function and add a call to the function as the last line of the script. I’ll be returning to this idea in a little while as I want to do some more on automating updates across my test environment

Read the Scripting Guy Blog

I had the pleasure of meeting Microsoft’s Scripting Guy, Ed Wilson and his charming wife at the recent PowerShell Deep Dive. As well as being very nice guy Ed also has a huge depth of knowledge on scripting in general and PowerShell in particular. His Hey, Scripting Guy! blog is one of the few I read on a regular basis. I might not always agree with Ed but he makes me think about some of the things I have come to take for granted about PowerShell.


If you don’t already read this blog now would be a good time to start – Ed is just starting a series about us stopping writing PowerShell scripts!!!  http://blogs.technet.com/b/heyscriptingguy/archive/2011/06/25/don-t-write-powershell-scripts.aspx.


No, I’m not going to tell you any more – go and read it and the subscribe to the RSS feed for the rest of the posts in the series.

Viewing favourites

I recently copied my favourites between machines which started me thinking about viewing favourites. Like many people I have generated a lot of favourites over the years – do I really need them all. Don’t know because I don’t know what they are.  Its easy to correct that

$favs = New-Object -ComObject Shell.Application            
Get-ChildItem -Path $favs.NameSpace(0x6).Self.Path -Recurse |            
where {-not $_.PSIsContainer} |            
foreach {            
 $fav = New-Object -TypeName PSObject -Property @{            
  Name = $_.BaseName             
 }            
             
 Get-Content -Path $_.FullName | foreach {            
  if ($_.StartsWith("URL=")) {            
   $fav | Add-Member -MemberType NoteProperty -Name URL -Value $_.Replace("URL=","")}            
 }             
 $fav            
}


The script use the Shell COM object to access the favourites special folder. We then iterate through the favourites and get the content of each favourite. These are just text files so we can pick out the URL. An object is created to hold the favourite name and URL and then displayed

PowerShell basics: using Get-Content to drive a copy

I recently saw a forum question about copying files where the file names where in a file

Icreated a file with the full path to the files that need to be copied

Get-ChildItem -path c:\test -Filter proc* | foreach {Add-Content -Value $_.Fullname -Path c:\test\files2copy.txt}

the content of the file can be seen

PS> Get-Content -Path c:\test\files2copy.txt
C:\test\proc1.txt
C:\test\proc2.txt

to copy the files to another folder

Get-Content -Path c:\test\files2copy.txt | foreach {Copy-Item -Path $_ -Destination c:\Teszzt2}

 

The trick with get-content is that it creates an array of strings – one per line of the file

Alternatively we could do this

$files = Get-Content -Path c:\test\files2copy.txt
foreach ($file in $files){Copy-Item -Path $file -Destination c:\Teszzt2}

 

the second option my be better if you need to perform further processing on the files

Colour highlighted code in posts

I’ve been having a bit of difficulty getting code highlighted code into my posts recently. I use Live Writer to publish the posts and I was using an ISEadd-in published by Lee Holmes to paste the code. This has stopped working recently. Nor sure why.

I remembered that the PowerShellPack of modules

http://archive.msdn.microsoft.com/PowerShellPack

included some ISE extensions.

I loaded the module through the ISE profile and on the Add-Ons tab there is a ISEpack entry. Under the Edit menu I tried Copy-Colored but it didn’t work properly with Live Writer. However, Copy-ColoredAsHTML does work.  It just means I have to paste the code into the source view of the post and then revert to the Edit view.

Not really that more fiddly than using the paste special functionality.

I suspect that the difficulties all lie with Live Writer but at least I can paste colour (notice I spell it correctly Smile ) highlighted code.