PowerShell MVP

July 4th, 2010 Niklas Goude 3 comments

Got back from a vacation in Australia today and found out that I had an e-mail from Microsoft in my inbox containing the following:

Dear Niklas Goude,

Congratulations! We are pleased to present you with the 2010 Microsoft® MVP Award! This award is given to exceptional technical community leaders who actively share their high quality, real world expertise with others. We appreciate your outstanding contributions in PowerShell technical communities during the past year.

It feels amazing receiving this award and Im really happy to be a part of the PowerShell MVP’s.

Thank You!

Rating 4.00 out of 5
[?]
Categories: Community Tags:

Australian & New Zealand SharePoint Conference

June 17th, 2010 Niklas Goude 1 comment

I just finished my Australian/New Zealand SharePoint & PowerShell tour with Mattias Karlsson where we had the honor to speak at both the New Zealand and the Australian SharePoint conference. In our session SharePoint 2010 and PowerShell – In real life we showed a couple of demos and promised to share them on this site. So here they are.

Click here to download the scripts

Click here to download the PowerPoint presentation

Rating 3.00 out of 5
[?]

Swedish PowerShell book release

April 4th, 2010 Niklas Goude No comments

I’ve finally completed the first Swedish PowerShell book. I released it on TechDays Sweden, where we gave it away for free and now I’ve released the book as an e-book. You can download the book at www.powershell.se or at www.powershell.nu.

The book focuses on getting started with Windows PowerShell and includes: Basic cmdlets, parameters, pipelines, functions, filters, security, writing scripts, learning .NET, WMI, COM and much more. The last chapter in the book focuses on how to administrate Windows environments through PowerShell which includes: managing folders and files, acl, services, eventlogs, processes, the registry, windows forms, Active Directory, Microsoft SQL Server, New functionality in Windows 7 and much more.

Note that the book is written in Swedish, so you might want to run it through google translator.. :)

Happy Reading.

Rating 3.00 out of 5
[?]
Categories: Book Tags:

Adding Announcements to SharePoint 2010 through PowerShell

January 27th, 2010 Niklas Goude No comments

SharePoint 2010 is on it’s way and it’s way cool. Lots of great CmdLets that simplify the SharePoint administrators life. In this post we are going to check out how to add Announcements to an Announcements list in SharePoint through PowerShell. First we’ll do it step-by-step in the “SharePoint 2010 Management Shell” (PowerShell shell that registers SharePoint CmdLets) and then we’ll look at a script that automates the task.

First, start the SharePoint 2010 Management Shell.

Now we can get fancy with SharePoint administration. Adding a new announcement is done basically in the same way as in MOSS, though it’s alot simpler since Microsoft added tons of new great SharePoint CmdLets. Below is an example on adding a new announcement to a SharePoint list.


PS > $siteScope = Start-SPAssignment
PS > $Announcement = ($siteScope | Get-SPWeb -identity http://sharepoint).Lists["Announcements"]
PS > $NewItem = $Announcement.Items.Add()
PS > $NewItem["Title"] = "My First Announcement"
PS > $NewItem["Body"] = "<h2>PowerShell Magic</h2>"
PS > $NewItem["Expires"] = "1/28/2010"
PS > $NewItem.Update()
PS > Stop-SPAssignment $siteScope

The Start-SPAssignment and Stop-SPAssignment should be used with certain objects such as SPSite, SPWeb and SPSiteAdministration, since they need to be disposed. You can read more about the CmdLets at the I Love SharePoint blog.

The rest of the code is pretty straightforward, Get the Web through Get-SPWeb, create an object holding the List, use the Add() method, add the information and finally update the new item using the Update() method.

Here’s what it looks like in the Shell.

Announcement

And here’s our new Item in SharePoint.

Announcement2

When put in a script, we can simply add a new announcement on a single line.


PS > Add-SharePointAnnouncement.ps1 -identity http://sharepoint -List Announcements -Title "Added From Script" `
>> -Body "<h2>PowerShell Scripts Rock</h2>" -Expires 1/28/2010

Click here to download the script.

Rating 3.00 out of 5
[?]
Categories: SharePoint 2010 Tags:

Running Scripts with arguments in PowerShell

December 16th, 2009 Niklas Goude No comments

Here’s a short guide on running scripts in powershell.

The guide is divided into three parts:

  • Running Scripts from the Console
  • Running Scripts from Start/Run
  • Running Scripts as Backgournd Jobs in PowerShell

First, let’s look at the script examples that we want to run.

Here’s the first script:

##################
#
# Script 1
#
##################

"Arguments: $($args.count)"
$args

And here’s the second script:

##################
#
# Script 2
#
##################

param($Argument1,$Argument2)

"Argument1 is: $Argument1"
"Argument2 is: $Argument2"

Script 1 uses $args variable to handle arguments. This is a automatic Variable created by PowerShell. It will handle any arguments that are passed to the script.

Script 2 uses a param statement. the param statement let’s us define variables that hold our arguments. The variables are available throughout the script.

Running Scripts from the Console

Now, let’s look at a couple of different ways of running scripts from the PowerShell console.


PS > C:\temp\Scripts\script1.ps1 Hello World

Arguments: 2
Hello
World

In the example, we triggered the script with two arguments, Hello and World. If we instead want Hello World to pass as a single argument, we can use quotation marks:


PS > C:\temp\Scripts\script1.ps1 “Hello World”

Arguments: 1
Hello World

In this example, There's only one argument passed to the script since "Hello World" is within quotation marks.

Obviously, we can use variables as arguments.


PS > $HelloWorld = "Hello World"
PS > $Hello = "Hello"
PS > $World = "World"

PS > C:\temp\Scripts\script1.ps1 $HelloWorld

Arguments: 1
Hello World

When we enter $HelloWorld, the value of the $HelloWorld variable is passed on as one argument to the script.

If we instead use the Variables $Hello and $World, they will be handled as two different arguments.


PS > C:\temp\Scripts\script1.ps1 $Hello $World

Arguments: 2
Hello
World

If we put the variables within quotation marks, they will be passed on to the script as one single argument.


PS > C:\temp\Scripts\script1.ps1 "$Hello $World"

Arguments: 1
Hello World

Using Single Quotation takes passes the argument exactly as written, in other words, the Argument will be $Hello $World and not the values of the variables.


PS > C:\temp\Scripts\script1.ps1 '$Hello $World'

Arguments: 1
$Hello $World

It's possible to achieve this when using Double Quotation marks. Just add a backtrick character in front of the variables.


PS > C:\temp\Scripts\script1.ps1 "`$Hello `$World"

Arguments: 1
$Hello $World

Let's look at a few examples on running Script 2 from the console. Script 2 uses the param statement.


PS > C:\temp\Scripts\script2.ps1 Hello World

Argument1 is: Hello
Argument2 is: World

In this example, Hello is assigned to $Argument1 and World is Assigned to $Argument2


PS > C:\temp\Scripts\script2.ps1 "Hello World"

Argument1 is: Hello World
Argument2 is:

If we put Hello World in double quotation marks, both Hello and World are assigned to $Argument1. $Argument2 is empty.

It's also possible to use the param variables as parameters to the script as the examples below show.


PS > C:\temp\Scripts\script2.ps1 -Argument1 Hello -Argument2 World

Argument1 is: Hello
Argument2 is: World

If we only specify one parameter the second will automatically be assigned to the first variable in the param that doesn't have a value.


PS > C:\temp\Scripts\script2.ps1 -Argument1 Hello World

Argument1 is: Hello
Argument2 is: World

PS > C:\temp\Scripts\script2.ps1 -Argument2 World Hello

Argument1 is: Hello
Argument2 is: World

You can, of course, use quotation marks here as well.


PS > C:\temp\Scripts\script2.ps1 -Argument1 "Hello World"

Argument1 is: Hello World
Argument2 is:

What if the Path to the script contains spaces ?. Let's see what happens. in these examples I've changed the path to the scripts to C:\Temp\Example Scripts\


PS > C:\temp\Example Scripts\script1.ps1 "Hello World"

The term 'C:\temp\Example' is not recognized as the name..

so this didn't work. It's because PowerShell separates commands with a space, so it tries to run the command C:\Temp\Example. You can solve this by using quotation marks and a Call Operator. without the Call Operator, PowerShell will handle the script path as a string value.


PS > & "C:\temp\Example Scripts\script1.ps1" "Hello World"

Arguments: 1
Hello World

Script2 can be triggered in the same way, note that the arguments are after the scriptpath and not within quotation marks.


PS > & "C:\temp\Example Scripts\script2.ps1" -Argument1 Hello -Argument2 World

Argument1 is: Hello
Argument2 is: World

Another way of running scripts is if you're in the same directory as the scripts are located. Then you can simply use the .\ notation in front of the script.


PS > cd 'C:\temp\Example Scripts\'
PS > .\script1.ps1 "Hello World"

Arguments: 1
Hello World

The easist way to run scripts is if you include the scriptpath in the environment PATH.


$Env:PATH = $Env:PATH + ";C:\Temp\Example Scripts"

Now we can simply type the name of the script to run it.


PS > script2.ps1 -Argument1 Hello -Argument2 World

Argument1 is: Hello
Argument2 is: World

You don't even have to type the script extension when running the scripts.


PS > script2 -Argument1 Hello -Argument2 World

Argument1 is: Hello
Argument2 is: World

Running Scripts from Start/Run

You can also trigger scripts from Start / Run in Windows. Here are a couple of examples on how we can run our scripts from Start / Run. The NoExit switch is used in these examples so that we can check the result easily.


powershell.exe -noexit C:\temp\Scripts\script1.ps1 Hello World

When running Scripts that are in a path that doesn't include spaces you can simply type the scripts FullPath followed by the arguments as shown in the example above. But what if you want "Hello World" to be handled as just one argument?


powershell.exe -noexit C:\temp\Scripts\script1.ps1 "Hello World"

If we type "Hello World" inside double quotation marks it's still handled as two different arguments. We can solve this by using Single Quotation Marks.


powershell.exe -noexit C:\temp\Scripts\script1.ps1 'Hello World'

Let's see how this works with the script that uses a param.


powershell.exe -noexit C:\temp\Scripts\script2.ps1 Hello World

This works just fine, lets specify the parameters in the script as well.


powershell.exe -noexit C:\temp\Scripts\script2.ps1 -Argument1 Hello -Argument2 World

And, as you can see, this works fine as well. Now let's see what happens if we double quote on of the arguments.


powershell.exe -noexit C:\temp\Scripts\script2.ps1 -Argument1 "Hello World" -Argument2 Monkey

This returns Hello as Argument1 and Monkey as Argument2. World is not in the script ouput. Now let's do the same example with single quotation marks.


powershell.exe -noexit C:\temp\Scripts\script2.ps1 -Argument1 'Hello World' -Argument2 Monkey

Now we got the result that we wanted. So lesson learned from this is: use single quotation marks when passing arguments containing spaces.

Now let's test this with the scripts containing spaces in the script path.


powershell.exe -noexit C:\temp\Example Scripts\script1.ps1 "Hello World"

This didn't work since the path contains spaces, now let's try it with double quotes at first.


powershell.exe -noexit "C:\temp\Example Scripts\script1.ps1" "Hello World"

Still no luck, lets try adding the Call Operator.


powershell.exe -noexit & "C:\temp\Example Scripts\script1.ps1" "Hello World"

In order to get it right, we have to use single quotation marks.


powershell.exe -noexit & 'C:\temp\Example Scripts\script1.ps1' "Hello World"

Note that Hello World is handled as two different arguments. Whe can solve this by typing Hello World within single quotation marks.


powershell.exe -noexit & 'C:\temp\Example Scripts\script1.ps1' 'Hello World'

Script 2, that uses the param statement works in the same way.


powershell.exe -noexit & 'C:\temp\Example Scripts\script2.ps1' -Argument1 Hello -Argument2 World

powershell.exe -noexit & 'C:\temp\Example Scripts\script2.ps1' -Argument1 'Hello World'  -Argument2 Monkey

Finally, let's see what happens if we run scripts included in the $Env:PATH variable.

First, we should add the script path to our profile so that it's loaded when powershell starts. Just Add $Env:PATH = $Env:PATH + ";C:\Temp\Example Scripts" into your profile.ps1 file.


powershell.exe -noexit script1.ps1 'Hello World'

powershell.exe -noexit script2.ps1 -Argument1 Hello -Argument2 World

We can even run the scripts without the extension.


powershell.exe -noexit script1 'Hello World'

powershell.exe -noexit script2 -Argument1 Hello -Argument2 World

Adding a script path to the $Env:PATH variable makes it alot more simple to run scripts in PowerShell.

Running Scripts as Backgournd Jobs in PowerShell

Let's take a look on how to run scripts as background Jobs. PowerShell v2 includes a great cmdlet callet Start-Job. It let's us run Jobs in the background. We can use this to run our scripts as background jobs.

Let's take a look on How to Run Scripts witth Start-Job.


PS > $Job1 = Start-Job .\script1.ps1 -ArgumentList Hello,World

By placing the command in a variable, we can easily access the Job informationm, check for status and use it to retrieve the output of the command. Start-Job Doesn't return the Job Result when completed so we have to use Receive-Job to get the Result from the Script.


PS > Receive-Job $Job1.ID
Arguments: 2
Hello
World
PS > Receive-Job $Job1.ID
PS >

When we run the Receive-Job CmdLet and use the Jobs ID as argument, we get the Result from the Job Returned. Note that if we run the same command again, we don't get anything returned. This is becauese Receive-Job, by default, deletes the Returned information after it's accessed. We can bypass this with the -Keep switch.


PS > $Job1 = Start-Job .\script1.ps1 -ArgumentList Hello,World
PS > Receive-Job $Job1.ID -Keep
Arguments: 2
Hello
World
PS > Receive-Job $Job1.ID -Keep
Arguments: 2
Hello
World

To Close the Session, run the Receive-Job command without the -Keep switch or use the Remove-Job CmdLet as shown below.


PS > Remove-Job $Job1.ID

So how to solve this without PowerShell V2 installed ? well, we could always use Wscript.Shell. Here's an example on running backgroundjobs with wscript.shell.


PS > $Wscript = New-Object -Com Wscript.Shell
PS > $Command = "powershell.exe & 'C:\temp\Example Scripts\script2.ps1' -Argument1 'Hello' -Argument2 'World'"
PS > $Wscript.Run($command,0,$False)
0

So how do we varify that the script actually runs ? Well, we can solve this with a simple pipeline.


PS > $Wscript = New-Object -Com Wscript.Shell
PS > $OutFile = "C:\temp\output.txt"
PS > $Command = "powershell.exe & 'C:\temp\Example Scripts\script2.ps1' -Argument1 'Hello' -Argument2 'World' | Out-File $OutFile"
PS > $Wscript.Run($command,0,$False)

0

PS > Get-Content $OutFile

Argument1 is: Hello
Argument2 is: World

Hope you find this guide useful.

Rating 3.00 out of 5
[?]
Categories: Basics, Scripting Tags: ,

#SEF09

November 19th, 2009 Niklas Goude No comments

First of all I would like o thank all the great people that attended the SharePoint and Exchange Forum 2009 here in Stockholm, Sweden.
Special Thanks to Göran Husman, Everyone at Humandata and all sponsors. Great work!

The international Speakers included Joel Oleson, Eric Shupps, Todd Klindt, Steve Smith and Penny Coventry.
On the Swedish team we got some great sessions from Wictor Wilén, Tobias Zimmergren and, of course, Göran Husman.

My session on SharePoint & PowerShell went well.. almost. The night before my presentation I decided to run through all my code examples one last time, which resultet in a USB-Disc crash. Unlucky for me was that my VMWare was stored on the USB-Disc.
So after half an hour of panic, 3 hours of installation and 1 hour of testing i finally got everything in place, just in time to get my morning coffee and head off to SEF. Anyway, you can download my presentation here or on www.seforum.se

Hope to see all y’all next year!

Rating 3.00 out of 5
[?]
Categories: Uncategorized Tags:

MOSS 2007 Script Collection

September 8th, 2009 Niklas Goude 10 comments

I’ve been working with SharePoint and PowerShell for quite some time now and I would like to share a couple of Scripts that I use when scripting MOSS. Actually, it’s 44 Scripts, Loads of Coffee and alot of long nights :) so I hope you enjoy them. There are Links at the bottom of the Post where you can Download all the scripts, or you can Download all scripts from the link below.

moss-script-collection.zip

Down to business then. I’ll put up a scenario based on the Session that I used at the SharePoint UserGroup meeting in Stockholm Sweden, explaining all Steps and how to use the Scripts.

First I set up a Folder where I keep all my scripts, I use C:\Scripts. Then I add the folder to the Windows Path.


PS > $env:path = $env:path + ";c:\scripts"

 

Adding the Script folder to the Environment Path let’s Us Call the script simply by typing it’s name. so instead of typing:


PS > .\Get-SPSite.ps1 -url http://moss

 

We can Type:


PS > Get-SPSite -url http://moss

 

Note, Don’t forget to set the Execution-Policy, otherwise, the scripts won’t run. Read more about it here


PS > Set-ExecutionPolicy RemoteSigned

 

All Scripts include a help text that explains how to use the Script. To access the helptext simply type the Script Name followed by -help.


PS > Get-SPSite -help

 

Now We can start Scripting MOSS!

Loading SharePoint Assemblies

 

The first thing we have to do in order to Access the MOSS 2007 Assemblies is Loading them into PowerShell. Even though they Exist in our Windows Environment, PowerShell isn’t aware of them. By Loading them into our Global Assembly Cache, PowerShell can access and use the MOSS 2007 .NET Classes.


[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

 

Get-SPSite.ps1

 

First, We’ll Check out the Site Collection. Here’s how we can add our Site Collection to a variable using the Get-SPSite.ps1 script and retrieve information from it. When working with SPSite or OpenWeb objects in the PowerShell console you have to dispose of the object on the same row as the command, otherwise they will leak memory. This only applies when you create SharePoint objects directly in the PowerShell console. When run in functions and scripts, the commands are run in a single thread. for more information click here


PS > $SPSite = Get-SPSite -url http://moss; $SPSite | Select Url, Port, Owner | Format-List; $SPSite.Dispose()

Url   : http://moss
Port  : 80
Owner : POWERSHELL\administrator

 
We can also get usage Information:


PS >  $SPSite = Get-SPSite -url http://moss; $SPSite.Usage; $SPSite.Dispose()


Storage           : 550113
Bandwidth         : 0
Visits            : 0
Hits              : 0
DiscussionStorage : 0

 

And even information from the WebApplication Pool 


PS > $SPSite = Get-SPSite -url http://moss; $SPSite.WebApplication.ApplicationPool | Select DisplayName, Status | Format-List; $SPSite.Dispose()


DisplayName : SharePoint - 80
Status      : Online

 

Try Pipe:ing the $SPSite object to Get-Mameber and check out all Available methods and properties available. 


PS > $SPSite = Get-SPSite -url http://moss; $SPSite | Get-Member; $SPSite.Dispose()

 

Get-SPWeb.ps1

 

The Get-SPWeb.ps1 Returns a Site instead of a Site Collection through the OpenWeb() method. Through it, we can modify the Title and description of a site, we can add Items, documents and lots more. Here’s an example on how you can change the Title and Descrition of a Site. 


PS > $OpenWeb = Get-SPWeb http://moss; $OpenWeb.Title; $OpenWeb.Dispose()

Home

PS > $OpenWeb = Get-SPWeb http://moss; $OpenWeb.Description; $OpenWeb.Dispose()

Home

PS >  $OpenWeb = Get-SPWeb http://moss; $OpenWeb.Title = "PowerShell Home"; $OpenWeb.Description = "Demo From PowerShell.nu"; $OpenWeb.Update(); $OpenWeb.Dispose()

 

Here’s What happened to my MOSS RootWeb Site after running these simple commands. 

moss01 

Get-SPList.ps1

 

We’ve accessed The Site Collection and a MOSS Site, Let’s look at how to access a List within a Site. We can do this through the Get-SPList.ps1 Script. We can use it to Get or Set List Information and even Get or Set Items and Fields in the List. 


PS > $SPList = Get-SPList -url http://moss -List Announcements; $SPList.ItemCount; $SPList.Dispose()

3

PS > $SPList = Get-SPList -url http://moss -List Announcements; $SPList.Items | ForEach { $_["Title"] }; $SPList.Dispose()

Get Started with Windows SharePoint Services!
Announcement Added through PowerShell
Demo from PowerShell.nu

 

Get-SPField.ps1

 

A List Contains Field which tell us what kind of information we can add to our Items. When Accessing a Field you can use the Get-SPField.ps1 script. The Field holds alot of information such as Type. 


PS > $Field = Get-SPField -url http://moss -List Announcements -Field Expires
PS > $Field.Type

DateTime

 

You can even edit information in the Field. Here’s an Example on How to Hide the Field in Edit Form. When a User Tries to Edit an item in the Announcements List, he won’t see the Expires Field. 


PS > $Field.ShowInEditForm = $False
PS > $Field.Update()

 

Get-SPView.ps1

 

A List Contains a Variaty of Views. Here’s how you Access a List View in MOSS 2007 using the Get-SPView.ps1 Script. 


PS > $View = Get-SPView -url http://moss -List "Shared Documents" -View "All Documents"

 

The View contains alot of Methods and Properties. Let’s take a look at the Clone() Method. 


PS > [void]$View.Clone("My Cloned View",100,$True,$False)

 

With this Simple Command, I’ve Created a new View Called “My Cloned View”. It’s basically a Copy of the “All Documents” View. 

Get-SPItem.ps1

 

When Accessing Items within a List, you can use the Get-SPItem.ps1 Script. Storing the Item in a Variable Allows us to Get And Modify it’s properties. The script includes an -All Switch that retrieves All Items in a List instead of just one item. 


PS > $Item = Get-SPItem  -url http://moss -List Announcements -Item "Get Started with Windows SharePoint Services!"

 

Now That we have an Item stored in the $Item Variable, we can Modify it. 


PS > $Item["Body"]

Microsoft Windows SharePoint Services helps you to be more eff ective by connecting people, information, and documents. For information on getting started, see Help.
PS > $Item["Body"] = "New Text in Body" PS > $Item.Update()

 

Another Nice Trick is Looping through all Items. First let’s Store them in a variable: 


PS > $AllItems = Get-SPItem -url http://moss -List Announcements -All

Now Let’s Set the Body on All Announcements in the Announcements List.


PS > $AllItems | ForEach { $_["Body"] = "New Text"; $_.Update() }

 

Add-SPAnnouncement.ps1

 

Next, let’s add an Announcement to our RootWeb Site. Using the Add-SPAnnouncement.ps1 sript, we can add through a One-Liner in PowerShell. 


PS > Add-SPAnnouncement -url http://moss -List "Announcements" -Title "Demo from PowerShell.nu" -Body "<h1>PowerShell</h1><p />is Cool!" -Expires (Get-Date).AddHours(1)

 

moss02 

Let’s say that you have multiple sites in your Site Collection and you want to add an Announcement on each site. This can be solved with a Simple ForEach: 


PS > $Sites = "http://moss/HR","http:moss/IT","http://moss/Production","http://moss/Sales"
PS > $Sites | ForEach {
>> Add-SPAnnouncement -url $_ -List "Announcements" -Title "Demo från PowerShell.nu" -Body "

is Coolt!" -Expires (Get-Date).AddHours(1)

 

This Code adds an announcement on each site in the $Sites Array. 

Add-SPCalendar.ps1

 

The Add-SPCalendar.ps1 script adds new Calendar Entries to a MOSS Calendar List. 


PS > Add-SPCalendar -url http://moss -List "Calendar" -Title "SharePoint - PowerShell Demo" -Location "Stockholm" -Description "PowerShell Demo" -StartTime (Get-Date) -EndTime (Get-Date).AddHours(4)

 

The -StartTime and -EndTime Parameters accept an [DateTime] object, which means that we can use the Get-date CmdLet to Add Dates. 

moss03 

Add-SPLink.ps1

 

Here’s a Script that adds Links to a MOSS Links List. It sets the Link, the Description of the Link and the Notes Field. 


PS > Add-SPLink -url http://moss -List "Links" -Link "http://www.powershell.nu" -Description "PowerShell.nu - Blog" -Notes "PowerShell Blog"

 

Here’s what our Newly created Link Item looks like: 

moss04 

Set-SPImageWebPart.ps1

 

On a Default installed MOSS, The Root Web uses the “Team Site” Template, which has an Image WebPart on the Right Displaying a SharePoint Services Image. Let’ go ahead and change the image using the Set-SPImageWebPart.ps1 Script. 


PS > Set-SPImageWebPart -url http://moss -WebPart "Site Image" -Image "C:\Demo\Files\PowerShell.jpg"

 

As you can see in the Image below, Our RootWeb Team Site looks a little PowerShelled. 

moss05 

Set-SPTheme.ps1

Now that we’ve customized our Site with a New “Site Image”, let’s go ahead and change the Theme. We’ll use the Set-SPTheme.ps1 script to achieve this.


PS > Set-SPTheme -Url http://moss -Theme obsidian

 

And with a simple One-Liner, we’ve changed the Theme on our Site. Doing without the script takes about two lines of code, but i Added the script since I think it’s pretty cool. 

moss06 

Upload-SPDocument.ps1

 

This Script lets you Upload Documents to a Document Library in MOSS. Here’s how it Works: 


PS > Upload-SPDocument -url http://moss -Folder "Shared Documents" -Document "C:\Documents\Excel SpreadSheet.xlsx"

 

If we look in our “Shared Documents” List, We can see that the Document is uploaded there now. 

moss07 

But What it we want to Upload one hundred documents ? Well, since we are using PowerShell, we can do it with a One-Liner. 


PS > gci C:\Documents | ForEach { Upload-SPDocument -url http://moss -Folder "Shared Documents" -Document $_.FullName }

 

This really shows the Power of Microsoft PowerShell 

Add-SPFolder.ps1

 

Now That we’ve Uploaded a couple of Files, Let’s Add a New Folder to our “Shared Documents”. We can do this by using the Add-SPFolder.ps1 script. 


PS > Add-SPFolder -Url http://moss -List "Shared Documents" -Name "New Folder"

 

If we want to Upload Documents Directly to our Folder we can use the Upload-SPDocument.ps1 Script again, we just point it to our New Folder. 


PS > Upload-SPDocument -url http://moss -Folder "Shared Documents/New Folder" -Document "C:\Documents\Excel SpreadSheet.xlsx"

 

Add-SPTextField.ps1

 

Let’s add a couple of Fields to our “Shared Documents” List. First, we’ll add a Document Owner Field. In this example we’ll use a simple Text field, but you could obviously use a User field instead. We’ll get back to the User field a little later in this post. 


PS > Add-SPTextField -url http://moss -List "Shared Documents" -Name "Document Owner" -Description "Document Owner"

 

This Adds a TextField to our List named “Document Owner”, if you want the field to Require information, simply add -Required to the command above. 

moss08 

Add-SPChoiceField.ps1

 

Next, We’ll add a Choice Field to our “Shared Document”. This can be done by using the Add-SPChoiceField.ps1 Script. Again, if you want the Field to Require information, just add -Required to the command. 


PS > Add-SPChoiceField -url http://moss -List "Shared Documents" -Name "Document Type" -Description "Type of Document" -Choices $("Excel","Word","PowerPoint")

 

Note the -Choices Paramteter. It takes an Array of arguments and Sets each argument as a Choice in the Field. Typing $(“Argument1″,”Argument2″) is a quick way to create an array and passing it as an argument to the script. 

moss09 

Add-SPFieldToView.ps1

 

Now that we have two new Fields in our “Shared Documents”, let’s add them to the “All Documents” View by using the Add-SPFieldToView.ps1 Script. 


PS > Add-SPFieldToView -url http://moss -List "Shared Documents" -Field "Document Owner" -View "All Documents"
PS > Add-SPFieldToView -url http://moss -List "Shared Documents" -Field "Document Type" -View "All Documents"

 

If we check out our “Shared Documents” list now, we can see that the Fields are Added to the “All Documents” View. You can, of course, use this on any type of List in MOSS 2007. 

moss10 

Set-SPItem.ps1

 

Here’s a Really Useful script when working with Items. The Set-SPItem.ps1 Script can either Create a New Item or Modify an existing Item. At first, Let’s take a look on how to Modify existing Items. By Default, the -field param is set to Title, but by changing it to Name, the script will check for a match in the Name Field and if it finds a match, it will update the Item, if it doesn’t find a match it will create a New Item. Note that when Creating Items in a Document Library you have to use the Upload-SPDocument.ps1 script. 

Note that the -Values takes a HashTable Array of Values to Set on the Item. Let’s say a List has Two Fields. A Title field and a Description Field. If I want to Create a New Item Called “New Item” and with The Description “My New Item Description” I could Simply type: 


PS > Set-SPItem -url http://moss -List "My List" -Name "New Item" -Values @{"Description" = "My New Item Description"}

 

If i Want to Edit the Item that i Created i Could reuse the Same Command, since it First looks for an Item Where the Title is Set to “New Item” 

Let’s say i Don’t know the Title of the Item but i Do know It’s Description. By using the -Field paramter i Could get the Correct Item and Modify it. 


PS > Set-SPItem -url http://moss -List "My List" -Name "My New Item Description" -Field Description -Values @{"Title" = "New Title"; "Description" = "Changed Title and Changed Description of Item"}

 

Let’s Take a Look at the Documents that we Added earlier. Here’s an example on adding MetaData on Documents in a Document Library:


PS > Set-SPItem -url http://moss -List "Shared Documents" -Name "Excel SpreadSheet.xlsx" -Field "Name" -Values @{"Document Type" = "Excel"; "Document Owner" = "Niklas Goude"}
PS > Set-SPItem -url http://moss -List "Shared Documents" -Name "Word Document.docx" -Field "Name" -Values @{"Document Type" = "Word"; "Document Owner" = "Niklas Goude"}
PS > Set-SPItem -url http://moss -List "Shared Documents" -Name "PowerPoint Presentation.pptx" -Field "Name" -Values @{"Document Type" = "PowerPoint"; "Document Owner" = "Niklas Goude"}

 

With these Commands I added information in the “Document Type” Field and the “Document Owner” Field on my three Documents, as the image below show. 

moss11 

Let’s Use this Script to Modify the Announcement That we Added Earlier. We’ll Change the Body of the Announcement. 


PS > Set-SPItem -url http://moss -List Announcements -Name "Demo from PowerShell.nu" -Values @{"Body" = "<h2>Modified With Set-SPItem.ps1</h2>"}

 

Here’s what the Announcemet looks like now: 

moss12 

Add-SPList.ps1

 

Now Let’s create our own Custom List. We’ll use the Add-SPList.ps1 Script to do this. Specifying the Type to “Custom List” tells the script to create a “Custom List”. You can, of course create any type of list available in MOSS through this script. 


PS > Add-SPList -url http://moss -Name "My List" -Description "My Custom Demo List" -Type "Custom List"

 

This Creates the List, but it doesn’t Add the List to the QuickLaunch Bar. Let’s check out how to Add a List to the QuickLaunchBar. 

Add-SPListToQuickLaunch.ps1

 

This Script adds lists to the Quicklaunch Bar in MOSS 2007. The Command below shows how you can use the script. 


PS > Add-SPListToQuickLaunch -url http://moss -List "My List"

 

This command adds the List to the QuickLaunch Bar. 

moss13 

Set-SPQuickLaunchOrder.ps1

 

Let’s Change the QuickLaunch Order. We’ll use the Set-SPQuickLaunchOrder.ps1 Script that moves a List to the Top of the QuickLaunch. 


PS > Set-SPQuickLaunchOrder -url http://moss -List "My List"

 

If we look at our site now, We can see that our QuickLaunch Order has been Changed. The “My List” List is now on top. 

moss14 

Now That we have a Custom List, Let’s Add a couple of different Fields, We’ll also add them to the “All Items” View with the Add-SPFieldToView.ps1 script. 

Add-SPCurrencyField.ps1

 

You can Add a Currency Field by using the Add-SPCurrencyField.ps1 Script. 


PS > Add-SPCurrencyField -url http://moss -List "My List" -Name Cash -Description "How much Money do you have?"
PS > Add-SPFieldToView -url http://moss -List "My List" -Field Cash -View "All Items"

 

Add-SPDateTimeField.ps1

 

Here’s how we can add a DateTime Field to a List using the Add-SPDateTimeField.ps1 Script. 


PS > Add-SPDateTimeField -url http://moss -List "My List" -Name "Birthday" -Description "When is Your Birthday?"
PS > Add-SPFieldToView -url http://moss -List "My List" -Field Birthday -View "All Items"

 

Add-SPNoteField.ps1

 

The Note Field Accepts Text on Multiple Rows. Here we add a Note Field using the Add-SPNoteField.ps1 Script. 


PS > Add-SPNoteField -url http://moss -List "My List" -Name Description -Description "About Me.."
PS > Add-SPFieldToView -url http://moss -List "My List" -Field Description -View "All Items"

 

Add-SPNumberField.ps1

 

We can also Add Numeric Fields to MOSS. This example shows how to do that using the Add-SPNumberField.ps1 Script. 


PS > Add-SPNumberField -url http://moss -List "My List" -Name Age -Description "How Old Are You?"
PS > Add-SPFieldToView -url http://moss -List "My List" -Field Age -View "All Items"

 

Add-SPYesNoField.ps1

 

With the Add-SPYesNoField.ps1 script, We can add a Yes/No Checkbox Field to our List. 


PS > Add-SPYesNoField -url http://moss -List "My List" -Name "Windows 7" -Description "Do You Have Windows 7 Installed?"
PS > Add-SPFieldToView -url http://moss -List "My List" -Field "Windows 7" -View "All Items"

 

Add-SPUserField.ps1

 

Adding User Fields that point to a Active-Directory User, Can be Added through the Add-SPUserField.ps1 Script. 


PS > Add-SPUserField -url http://moss -List "My List" -Name User -Description "User"
PS > Add-SPFieldToView -url http://moss -List "My List" -Field User -View "All Items"

 

Add-SPMultipleUserField.ps1

 

A User Field can Allow Multiple Selections. Here’s how to add a multiple User Field using the Add-SPMultipleUserField.ps1 script. 


PS > Add-SPMultipleUserField -url http://moss -List "My List" -Name "Multiple Users" -Description "Multiple Users"
PS > Add-SPFieldToView -url http://moss -List "My List" -Field "Multiple Users" -View "All Items"

 

Add-SPMultiChoiceField.ps1

 

Choice Fields can also accept Multiple Choices. Here’s an example on how to add a Multiple Choice Field using the Add-SPMultiChoiceField.ps1 Script. 


PS > Add-SPMultiChoiceField -url http://moss -List "My List" -Name "Favorite Music" -Description "Favorite Music" -Choices $("Country","Metal","Rock","Soul","Jazz")
PS > Add-SPFieldToView -url http://moss -List "My List" -Field "Favorite Music" -View "All Items"

 

Add-SPLookupField.ps1

The Lookup Field Points to an Item in another List. In this Example we’ll Point it to the “Tasks” List.


PS > Add-SPLookupField -url http://moss -List "My List" -Name "My Tasks" -Description "My Tasks" -LookupList Tasks
PS > Add-SPFieldToView -url http://moss -List "My List" -Field "My Tasks" -View "All Items"

 

Add-SPMultiLookupField.ps1

 

LookupFields Can also have multiple Values. We can add a Multiple LookupList through the Add-SPMultiLookupField.ps1 Script. Again, We’ll Use the Tasks List as Lookup. 


PS > Add-SPMultiLookupField -url http://moss -List "My List" -Name "Multiple Tasks" -Description "Multiple Tasks" -LookupList Tasks
PS > Add-SPFieldToView -url http://moss -List "My List" -Field "Multiple Tasks" -View "All Items"

 

Add-SPURLField.ps1

 

Finally, Let’s Add an URL Field to our “Custom List”. 


PS > Add-SPURLField -url http://moss -List "My List" -Name HomePage -Description "HomePage"
PS > Add-SPFieldToView -url http://moss -List "My List" -Field HomePage -View "All Items"

 

Now, Let’s see what our List Looks like. 

moss15 

Let’s Add Two Task Items and then create a New Item in our “Custom List” using the Set-SPItem.ps1 Script. 


PS > Set-SPItem -url http://moss -List Tasks -Name "My First Task" -Values @{"Priority" = "(3) Low"; "Status" = "In Progress"; "% Complete" = "0.4"; "Assigned To" = "powershell\Administrator"; "Description" = "My First Task"; "Start Date" = "09/07/09"; "Due Date" = "09/08/09"}
PS > Set-SPItem -url http://moss -List Tasks -Name "My Second Task" -Values @{"Priority" = "(1) High"; "Status" = "Not Started"; "% Complete" = "0"; "Assigned To" = "powershell\Administrator"; "Description" = "My Second Task"; "Start Date" = "09/07/09"; "Due Date" = "09/08/09"}

 

Here’s our New Tasks up and running. 

moss16 

Now Let’s Add a New Item in our “Custom List”. Note that Fields that Allow multiple Values are divided by a ; in the command below. For Instance, if I want to two values to a multiple Choice Field I would have to Type: @{“MultiChoiceField” = “Value1; Value2; Value3″}.


PS > Set-SPItem -url http://moss -List "My List" -Name "My First Item" -Values @{"Cash" = "10"; "Birthday" = "05/05/1982"; "Description" = "My First Entry"; "Age" = "27"; "Windows 7" = "Yes"; "User" = "powershell\administrator"; "Multiple Users" = "powershell\administrator; powershell\nigo"; "Favorite Music" = "Metal; Country"; "My Tasks" = "My First Task"; "Multiple Tasks" = "My First Task; My Second Task"; "HomePage" = "http://www.powershell.nu; My Blog" }

 

And Here’s what our Item Looks like in MOSS 2007. 

moss17 

Set-SPView.ps1

Let’s Modify the Apperance of the “All Tasks” View in the Tasks List so that it Groups By Status. When Modifying appearance of a View, We change the View Query. This can be Done by using the Set-SPView.ps1 Script.


PS > Set-SPView -url http://moss -List Tasks -View "All Tasks" -Query ''

 

Here’s what our Tasks Look like now. 

moss18 

Remember the “Shared Documents that We Added Fields to earlier ? Let’s Group the “All Documents” View by one of our New Fields. Note that the Name=”Document_x0020_Type” in the Query. It’s because the Field has Spaces in its Name. 


PS > Set-SPView -url http://moss -List "Shared Documents" -View "All Documents" -Query ''

 

And now our Documents are Grouped by “Document Type”. 

moss19 

Add-SPSpite.ps1

 

With the Add-SPSite.ps1 Script, we can add New Sites to our Site Collection. There are a Couple of Different Templates that we can use. To get a list of all templates available, SImply type the following commands. 


PS > $OpenWeb = Get-SPWeb http://moss; $OpenWeb.GetAvailableWebTemplates(1033) | Select Name; $OpenWeb.Dispose()

 

Let’s Create a New Site For our IT Department. 


PS > Add-SPSite -url http://moss -weburl "IT" -Title "Information Technology" -Description "IT Department" -Template "STS#1"

 

Here’s What the Site looks like now. 

moss20 

Since we used a STS#0 Template, the Site doesn’t contain any Lists or information. 

Add-SPGroup.ps1

 

If we want to Add a New Group to our Site Collection we can use the Add-SPGroup.ps1 Script. Here’s an example on using the Script. 


PS > Add-SPGroup -url http://moss -Group "New Group" -Role Read -Owner "powershell\administrator"

 

Now our “New Group” is Added to our Site with “Read” Permissions 

moss21 

Add-SPUser.ps1

 

With our New Group set up, we can go ahead and add users to it. To accomplish this, we can use the Add-SPUser.ps1 Script. Here’s an example on adding a User to the “New Group”.


PS > Add-SPUser -url http://moss -Group "New Group" -Domain "powershell.nu" -sAMAccountName "goude" -mail "niklas.goude@zipper.se" -FullName "Niklas Goude"

 

If we look in the Group now, our User will be added. 

moss22 

Add-SPSitePermission.ps1

 

Let’s Give our Group Full Permissions on The IT Site that we created earlier.


PS > Add-SPSitePermission -url "http://moss/IT" -Group "New Group" -Permission "FullMask"

 

Now all users in the Group have Full Permissions on the “IT” Site. On the RootWeb, they still have Read Permissions. 

Add-SPImageWebPart.ps1

 

Let’s Add a New Image WebPart to the IT Site that we just created. Here’s an example on how to do it using the Add-SPImageWebPart.ps1 Script.


PS > Add-SPImageWebPart -url http://moss/IT -Name "My Image" -Image "C:\Images\PowerShell.jpg" -ChromeType "None"

 

Now the Image WebPart is Added to the Site. There are a couple of parameters you can use with this script. simply type Add-SPImageWebPart -help to check out available parameters. 


PS > Add-SPImageWebPart -help

 

moss23 

Add-SPListViewWebPart.ps1

 

The Add-SPListViewWebPart.ps1 let’s us Add list View WebParts to our Sites. The Script contains a couple of parameters that let’s you choose Chrome Type, Zone and a couple of other things. Here’s an example on Using the Script.


PS > Add-SPListViewWebPart -url http://moss -List "My List" -Name "Client Statistics" -ChromeType "None"

 

Here’s our New List WebPart in Action! 

moss24 

Remove-SPField.ps1

 

If you want to Remove a Field From a List you can use the Remove-SPField.ps1 Script. Here’s an example on how to use the Script.


PS > Remove-SPField -url http://moss -List "Shared Documents" -Field "Document Type"

 

Remove-SPItem.ps1

 

If you want to Remove a List Item you can use the Remove-SPItem.ps1 script. The -name parameter matches with the Title field by default. If you want to match the name with another field, simply use the -field parameter.


PS > Remove-SPItem -url http://moss -List Tasks -name "My First Task"
PS > Remove-SPItem -url http://moss -List Tasks -name "Not Started" -Field Status

 

Remove-SPList.ps1

 

If you want to Remove an entire List you can use the Remove-SPList.ps1 script,


PS > Remove-SPList -url http://moss -List Tasks

 

This Command Removed the Tasks List from the RootWeb Site. 

Remove-SPSite.ps1

 

When Removing a Site from MOSS 2007 You can use the Remove-SPSite.ps1 script. This exmaple shows how to remove the IT Site that we created earlier.


PS > Remove-SPSite -url http://moss/IT

 

Export-SPSite.ps1

 

Let’s take a Backup of our Site Collection. We can either do this through Central Administration, through an STSADM Command or by Using PowerShell. This Example shows how to use a PowerShell Script to take a Backup of a Site Collection.


PS > Export-SPSite -url http://moss -file Backup.bak -Location C:\Backup\

 

The Command Places a Backup file in C:\Backup\Backup.bak. to automate this you could set up a Scheduled Task that takes a backup at specified weekdays. 

Import-SPSite.ps1

 

Now That we have a Backup, Let’s restore our Site Collection from the Backup file. To achieve this, we can use the Import-SPSite.ps1 Script. Here’s an example on how to use the script.


PS > Import-SPSite -url http://moss -file Backup.bak -Location C:\Backup\

 

Here’s a List of All scripts from this Post. Enjoy! 

Regards

Goude 

 

Rating 3.00 out of 5
[?]
Categories: MOSS, Sharepoint Tags: ,

Scripting PDF Documents through PowerShell

September 8th, 2009 Niklas Goude 3 comments

Microsoft Office Supports Scripting possibilities through Com Objects. But what about PDF Documents ? Luckily there is a DLL available for download that let’s us Create PDF documents through .NET

First you have to Download the ITextSHarp.dll

Next, Time for some PowerShell Magic.

Step One: Load the DLL.


PS > [System.Reflection.Assembly]::LoadFrom("C:\itextsharp\itextsharp.dll")

Step Two: Create a Variable holding the iTextSharp.text.Document Object


PS > $Doc = New-Object iTextSharp.text.Document

Step Three: Create a PDF Document with a connection to the $Doc variable


PS > [void][iTextSharp.text.pdf.PdfWriter]::GetInstance($Doc, [System.IO.File]::Create("C:\PDF\Goude.pdf") )

Step Four: Open The Document ( In order to add information to the PDF File )


PS > $Doc.Open()

Step Five: Create a Text Chunk and append Text to Display in Pdf Document


PS > $Chunk = New-Object iTextSharp.text.Chunk
PS > [void]$Chunk.Append(“Demo From PowerShell.nu”)

Step Six: Add the Chunk of Text, Set an Author with the AddAuthor() method and finally Close it with the Close() method


PS > $Doc.Add($Chunk)
PS > $Doc.AddAuthor("Niklas Goude")
PS > $Doc.Close()

Voila, you now have a PowerShell made PDF File. You can, of course, create far more advanced PDF files containing tons of information. I’ll get back to this in a later Post.

Rating 3.00 out of 5
[?]
Categories: .NET Tags:

Scripting Mp3 Tags through PowerShell

September 4th, 2009 Niklas Goude 1 comment

Structuring up you Music Library can be a rather time consuming task. You can however script this rather easily through PowerShell using the taglib-sharp library.

Let’s start off by downloading the Tag-Lib Library
Next, We have to Load the Assembly from PowerShell in order to access the Classes.


PS > $TagLib = "C:\taglib\Libraries\taglib-sharp.dll"

PS > [System.Reflection.Assembly]::LoadFile($TagLib)


GAC    Version        Location
---    -------        --------
False  v2.0.50727     C:\taglib\Libraries\taglib-sharp.dll

Now that we’ve loaded the dll, we need a music file that we want to set properties on, in this example I’m going to use a mp3 file. If we check out the properties on the mp3 file, we can see that nothing is set.

taglib01

Let’s change this through PowerShell. We have to create a variable using the [Taglib.File] Class and use the filepath as an argument to the Create() method.


PS > $Media  =  [TagLib.File]::Create("C:\Music\My Song.mp3")

The object contains a couple of Properties.


PS > $Media


Tag                    : TagLib.NonContainer.Tag
Properties             : TagLib.Properties
TagTypesOnDisk         : Id3v1, Id3v2
TagTypes               : Id3v1, Id3v2
Name                   : C:\temp\My Song.mp3
MimeType               : taglib/mp3
Tell                   : 0
Length                 : 0
InvariantStartPosition : 4608
InvariantEndPosition   : 7109078
Mode                   : Closed

The one that We’re interested in is the Tag property, which contains additional underlaying properties and methods. Let’s check it out:


PS > $Media.Tag


StartTag             : TagLib.NonContainer.StartTag
EndTag               : TagLib.NonContainer.EndTag
TagTypes             : Id3v1, Id3v2
Tags                 : {Audiograbber 1.83.01, LAME d
                       v2.PrivateFrame TagLib.Id3v2.
Title                :
Performers           : {}
PerformersSort       : {}
AlbumArtistsSort     : {}
AlbumArtists         : {}
Composers            : {}
ComposersSort        : {}
TitleSort            :
AlbumSort            :
Album                :
Comment              :
Genres               : {}
Year                 : 0
Track                : 0
TrackCount           : 0
Disc                 : 0
DiscCount            : 0
Lyrics               :
Grouping             :
BeatsPerMinute       : 0
Conductor            :
Copyright            :
Pictures             : {}
IsEmpty              : True
Artists              : {}
FirstArtist          :
FirstAlbumArtist     :
FirstAlbumArtistSort :
FirstPerformer       :
FirstPerformerSort   :
FirstComposerSort    :
FirstComposer        :
FirstGenre           :
JoinedArtists        :
JoinedAlbumArtists   :
JoinedPerformers     :
JoinedPerformersSort :
JoinedComposers      :
JoinedGenres         :

Let’s go ahead and set a couple of Values.


PS > $Media.Tag.Performers = "Goude"
PS > $Media.Tag.AlbumArtists = "Goude"
PS > $Media.Tag.Artists = "Goude"
PS > $Media.Tag.Album = "My Album"
PS > $Media.Tag.Genres = "Rock"
PS > $Media.Tag.Track = "1"
PS > $Media.Tag.Title = "My Song"
PS > $Media.Tag.Year = "2009"
PS > $Media.Tag.Comment = "PowerShell Demo"
PS > $Media.Save()

If we check out the file properties through Explorer we’ll see that the properties are set on the file.

taglib02

So, editing one file is easy, but what if you want to edit a couple of thousand files..

When I did this on my Media Files i used the Folder and File Names as reference. The folder and file structure was set up accordingly:


C:\Music\Rock\Artist1 – Album\01 – First Song.mp3
C:\Music\Rock\Artist1 – Album\02 – Second Song.mp3
C:\Music\Rock\Artist2 – Album\01 – First Song.mp3

So with this information i could make a script that Used this information in order to set the Tags. The script uses the “Rock” folder name as Genre, Then it Splits the “Artist – Album” folder and sets Artist = Artist and Album = Album, finally it splits the file name “01 – First Song.mp3″ and sets Track = 01 and Title = First Song. I’ve also error handling in the script so that You can follow up on files that didn’t pass through the script.

Click Here to download the Script

Examples on Running the script:


PS > Set-Media.ps1 -Folder C:\MyMusic\Rock -LogFile C:\Log\SetMediaLog.txt

Note! You can always modify the script to fit your own environment and folder structure.

Rating 3.00 out of 5
[?]
Categories: Media Tags:

Managing Local Groups through PowerShell

July 6th, 2009 Niklas Goude No comments

When managing Local Groups through PowerShell, we can use the [ADSI] type adapter.
Starting off, We have to connect to the Local Group that we want to modify.


PS > $ComputerName = $env:COMPUTERNAME
PS > $Group = "Administrators"
PS > $LocalGroup = [adsi]"WinNT://$computerName/$Group,group"
PS > $LocalGroup


distinguishedName :
Path              : WinNT://Computer01/Administrators,group

Now that we’re connected to the Local Group, we can start of by adding a user. First let’s add a Local User.


PS > $Domain = "powershell"
PS > $UserName = "nigo"
PS > $LocalGroup.Add("WinNT://$Domain/$userName")

This adds the Domain user powershell\nigo to the local Administrators Group. If we instead want to add a Local User, we just replace the Domain Name with the Local COmputer Name.


PS > $ComputerName = $env:COMPUTERNAME
PS > $LocalGroup.Add("WinNT://$ComputerName/$userName")

And if we want to remove a User from a local Group, we use the Remove() method.


PS > $Domain = "powershell"
PS > $UserName = "nigo"
PS > $LocalGroup.Remove("WinNT://$Domain/$userName")

Here’s a script that automates these tasks.

Click here to download the script.

Here are some examples on running the script.


PS > Set-LocalGroup.ps1 -UserName nigo -Add

PS > Set-LocalGroup.ps1 -UserName nigo -Remove

PS > Set-LocalGroup.ps1 -UserName nigo -Group "Guests" -Domain powershell -Add

PS > Set-LocalGroup.ps1 -help

Rating 3.00 out of 5
[?]

Managing Local Accounts through PowerShell

July 6th, 2009 Niklas Goude No comments

When managing Local Accounts through PowerShell, it’s possible to use the [ADSI] type adapter.
Starting off, let’s look at how to connect to the Local Computer.


PS > $ComputerName = $env:COMPUTERNAME
PS > $Computer = [adsi]"WinNT://$ComputerName"
PS > $Computer


distinguishedName :
Path              : WinNT://Computer01

Now that we have a variable holding the reference to our local computer, we can go ahead and add a Local User Account. This is done through the Create Method on the object. we’ll also add a Password for our User.


PS > $UserName = "NewUser"
PS > $Password = "Password1"
PS > $User = $Computer.Create("user",$UserName)
PS > $User.SetPassword($Password)
PS > $User.SetInfo()

And it’s as simple as that. If you’r running Windows 7 you have to start PowerShell with elevated rights in order to get it to work.

Removing the User is done by using the Delete() method.


PS > $Computer.Delete("user",$UserName)

Here’s a script i wrote that adds, removes or resets the password of a local User Account.

Click here to download the script

Examples on running the Script:


PS > Set-LocalAccount.ps1 -UserName NewUser -Password Password1 -Add
PS > Set-LocalAccount.ps1 -UserName NewUser -Password Password2 -ResetPassword
PS > Set-LocalAccount.ps1 -UserName NewUser -Remove

Rating 3.00 out of 5
[?]

Get-PrinterInformation

June 18th, 2009 Niklas Goude No comments

Gathering Printerinformation can be done through WMI. Win32_Printer contains information about printers that are used by a computer and Win32_PrinterDriver contains information about the printer drivers. We can combine these 2 WMI classes and retrieve information about both the printer and it’s drivers. This script checks for the following properties:

Computer             : Client1
Name                 : \\SERVER\SRV-FLOOR1-SV01
DefaultPrinter       : True
DriverName           : HP LaserJet 4250 PCL 6
DriverPath           : C:\Windows\system32\spo...
Driverdll            : UNIDRV.DLL
HorizontalResolution : 600
VerticalResolution   : 600
LocalPrinter         : False
PrintProcessor       : HPZPP4wm
Location             : GOT
Comment              : Company Printer
Description          : Printer on Floor 1

I’ve included a switch that let’s you pipe the information to a csv instead of displaying it to the host, and if you pipe an array of computer names to the script you can retrieve information from multiple computers.

Running the Script:


PS > .\Get-PrinterInformation.ps1 -Computer Client1 -ToCsv

PS > "Client1","Client2","Client3" |
>> ForEach { .\Get-PrinterInformation.ps1 -Computer $_ }

Here’s a link to the script.
Get-PrinterInformation.ps1

Rating 3.00 out of 5
[?]

Joining a Windows 7 Client to a Domain through PowerShell

June 5th, 2009 Niklas Goude 2 comments

Time to join a Windows 7 client to a domain. Now that the Test Domain is up and running ( Check Previous Posts ), we can start joining clients to the domain.

Since it’s a freshly installed Windows 7 client, we dont have to bother about userprofiles and so on.. we’ll save that for later :)

Joining the domain is done through WMI. Just create a new Object containing the Win32_ComputerSystem WMI object and call the JoinDOmainOrWorkGroup() method.


function JoinDomain ([string]$Domain, [string]$User, [string]$Password ) {

	$DomainUser = $Domain + "\" + $User
	$OU = $null

	$ComputerSystem = gwmi Win32_ComputerSystem

	$ComputerSystem.JoinDomainOrWorkGroup(
		$Domain,
		$Password,
		$DomainUser,
		$OU,
		3
	)
}

Here’s an example on running the function.


PS > JoinDomain PowerShell.nu migaccount Password1

And voila! the client shuts down and on Startup, It’ll have joined the new domain.

Rating 3.00 out of 5
[?]
Categories: Projects, Windows 7 Tags: ,

Write-StickyNote

June 5th, 2009 Niklas Goude No comments

Here’s a fun script that uses the new “Sticky Notes” in WIndows 7.

The script is based on a simple function that uses the SendKeys() method through the Wscript.Shell COM object. This is a nice example on how you can handle COM objects through PowerShell.

I’ve also included an if statement that checks if StickyNotes is active. If that’s the case, the text will be started in a new StickyNotes.. note..

Anyway, here’s the function.


function Write-StickyNote ([string]$Text) {

	if (gps | Where { $_.ProcessName -match "stikynot" }) {

		$StickyNote = $True
	}

	$Wscript = New-Object -Com Wscript.Shell
	[void]$Wscript.Run("stikynot.exe")
	start-sleep 1

	if ($StickyNote -eq $True) {

		$Wscript.SendKeys("^n")
	}

	$Wscript.SendKeys($Text)
}

And here’s an example on running the function.


PS > .\Write-StickyNote.ps1 "Hello from PowerShell.nu"

stickynotes01

Click here to download the Script

Rating 3.00 out of 5
[?]
Categories: COM Object, Windows 7 Tags:

Adding HomeFolder Through PowerShell

April 27th, 2009 Niklas Goude No comments

It’s been some time since my last post now, had alot of things to do at work, but now I’m back OnTrack with my blogging.

Last time we checked out how to add group membership through PowerShell, so now we should have a nice test environment in place, based on Star Trek.

In this post, we are going to script up Users homefolders and add each user to the correct folder. We’ll accomplish this through the following four steps:

  • Add a Share on the Server
  • Add unique folders for all Users
  • Add unique Permissions to the FOlders
  • Edit the User Objects in Active-Direcroty

I’m also going to re-use a script I wrote a couple of months ago, but we’ll get back to that.

Let’s start off by creating a Share. This can be done through the Create() method in the WMI class Win32_Share. The Win32_Share is well described in MSDN.

Since we want to make the script re-usable, we should check if the Share already exists. This is a simple procedure through PowerShell.


PS > $Share = "C:\Share"
PS > $ShareName = "Share"
PS > if ((gwmi Win32_Share | Where { $_.Path -eq $Share}).Path -eq $Share ) {
>>  Write-Host "Share: $ShareName already exists." -ForeGroundColor Red
>>  }

If the Share Already exists “Share: Share already exists” will be prompted, if not we can continue with the script.

Now that we know that the share doesn’t exist, we have to check that the folder exists, and if not, create the folder.


PS > if (!(Test-Path $Share)) {
>>  New-Item -Path $Share -type directory | Out-Null
>>  }

and finally, we can create our Share through WMI. Setting type to 0 creates a Disk Drive Share.


PS > $CreateShare = [wmiclass]"Win32_Share"
PS > $CreateShare.Create($Share,$ShareName,$Type) | Out-Null

add-stshare02

Now that the share is up and running, we can create our HomeFolders. First we set up our HomeDrive and HomeFolder variables, we’ll also set up a User for the example.


PS > $Share = "Share"
PS > $User = "jeapic"
PS > $HomeDrive = "H"
PS > $HomeDirectory = "\\" + $env:COMPUTERNAME + "\" + $Share + "\" + $User

Since the script runs on the server where the Share is created, we can use the environment variable to retrieve the computername.

Next, we want to check if the user already has the homedrive and homedirectory set. We can use the Get-AD.ps1 script for this. I’m also adding the -ToObject switch since i want to use the object later on.


PS > $GetUser = ./Get-AD.ps1 -Domain $Domain -User $User -Filter sAMAccountName -ToObject
PS > if ($GetUser.homeDirectory -match $HomeDirecory -AND $GetUser.homeDrive -match $HomeDrive) {
>> Write-Host "User: $User HomeDrive Already Set" -ForeGroundColor Yellow
>> }

If the User already has the HomeDrive set, we won’t continue, if not, we can go ahead and add it. But before connecting the User to the folder, want to create and give the user FullControl of his HomeFolder. Here we can use the Set-FolderPermission.ps1 script


PS > $Domain = "powershell.nu"
PS > $DomainUser = $Domain + "\" + $User
PS > ./Set-FolderPermission.ps1 -Path $HomeDirectory -Access $DomainUser -Permission FullControl

The Set-FolderPermission.ps1 both created the folder and set up the permissions for us, now all we have to do is set HomeDrive and HomeDirectory to the User Object.


PS > $GetUser.Put("homeDirectory",$HomeDirectory)
PS > $GetUser.Put("homeDrive",$HomeDrive)
PS > $GetUser.SetInfo()

And that’s it.

Running the script Doesn’t require the Star Trek Csv file used in the other examples, it does however require you to loop through each Users that you want to add Homefolders to. In order to get a list of all Users within an OU you can use the Get-AD.ps1 script, as shown below.


PS > ./Get-AD.ps1 -domain "LDAP://OU=Star Trek: The Next Generation,DC=powershell,DC=nu" -User AllUsers -Property sAMAccountName | ForEach {
>> ./Add-STHomeFolder.ps1 -Domain powershell.nu -User $_.sAMAccountName -Share Share -HomeDrive H
>> }

All I have to do now is change the LDAP path above and repeat the ForEach on each OU that contains Users that I want to add a HomeFolder to.

Here are a couple of screenshots on running the scripts:

add-sthomefolder

add-sthomefolder02

Click Here to Download the Add-STShare.ps1 Script.

Click Here to Download the Add-STHomeFolder.ps1 Script.

The Get-AD.ps1 script is also required.

Here’s the Set-Foldepermission.ps1 Script that’s also required.

Rating 3.00 out of 5
[?]

Adding Group Membership Through PowerShell

April 16th, 2009 Niklas Goude No comments

Time to add some members to our groups. Following the steps in the previous posts, we should now have a couple of Users, groups and computers in our test environment. Group Names are based on the Character position in the Star Trek Csv file so now, all we have to do is match up the Characters with their Positions.

Starting of, Let’s collect the information we need from the Csv File.

There are 68 Characters in the file so I’m only going to select the first one in the eample below.


PS > $CsvFile = Import-Csv StarTrek.csv
PS > ($CsvFile | Select Character, Position, Series)[0] | fl


Character : Jean-Luc Picard
Position  : Commanding Officer
Series    : Star Trek: The Next Generation

What we want to do now is add each member to the correct group. Let’s take the first User, Captain Picard, as an example and see how this is done.

Since there are 4 different Commanding Officer groups, we want to make sure that we connect to the correct one. We know which Starship (OU) the Captain is in since and we have that information in the Csv file so we can use this in combination with the Get-AD.ps1 script.

First we have get the OU:s distinguishedName.


PS > $Domain = "powershell.nu"
PS > $Series = "Star Trek: The Next Generation"
PS > $OU = ./Get-AD.ps1 -Domain $Domain -OU $Series -property distinguishedName
PS > $OU


distinguishedName
-----------------
OU=Star Trek: The Next Generation,DC=powershell,DC=nu


PS > $DomainConnection = "LDAP://" + [string]$OU.distinguishedName
PS > $DomainConnection

LDAP://OU=Star Trek: The Next Generation,DC=powershell,DC=nu

Now that we have the connectionstring, we can use this to narrow down the search in the Get-AD.ps1 script. By typing -Domain followed by an OU:s distinguishedName forces the script to only search within the OU structure.


PS > $Character = "Jean-Luc Picard"
PS > $User = ./Get-AD.ps1 -Domain $DomainConnection -User $Character -property distinguishedName, Name
PS > $UserConnection = "LDAP://" + [string]$User.distinguishedName
PS > $UserConnection

LDAP://CN=Jean-Luc Picard,OU=Users,OU=Star Trek: The Next Generation,DC=powershell,DC=nu

PS > $UserdistinguishedName = [string]$User.distinguishedName
PS > $UserdistinguishedName

CN=Jean-Luc Picard,OU=Users,OU=Star Trek: The Next Generation,DC=powershell,DC=nu

So why bother to create one variable holding the distinguishedName and one holding the LDAP connection string ?? well, we’ll get to that in a while but first we need a connection to the group as well.


PS > $Position = "Commanding Officer"
PS > $Group = ./Get-AD.ps1 -Domain $DomainConnection -Group $Position -ToObject
PS > $Group | Format-List *


objectClass          : {top, group}
cn                   : {Commanding Officer}
description          : {Commanding Officer}
distinguishedName    : {CN=Commanding Officer,OU=Groups,OU...
instanceType         : {4}
whenCreated          : {4/15/2009 5:09:08 PM}
whenChanged          : {4/15/2009 5:09:08 PM}
uSNCreated           : {System.__ComObject}
uSNChanged           : {System.__ComObject}
name                 : {Commanding Officer}
objectGUID           : {74 231 168 162 107 193 157 74 161
objectSid            : {1 5 0 0 0 0 0 5 21 0 0 0 50 71 101...
sAMAccountName       : {COMMANDIN}
sAMAccountType       : {268435456}
groupType            : {-2147483646}
objectCategory       : {CN=Group,CN=Schema,CN=Configuratio...
nTSecurityDescriptor : {System.__ComObject}

Now that we got the correct group, all we have to do is make a simple check so that the Captain isn’t already member of the group and if not, add him to it. Here’s where the distinguishedName and LDAP string come in handy.


PS > if ($Group.member -Contains $UserdistinguishedName) {
Write-Host “The Captain is already member”
} else {
$Group.Add($UserConnection)
}

Now let's how the complete script would handle this.

add-stmember01

Repeating the script tells us that the Characters are already members of the groups.

add-stmember02

And here's a quick check in the Active-Directory snapin.

add-stmember03

Click Here to Download the Complete Script.

The Get-AD.ps1 script is also required.

Click here to download the Csv File

Rating 3.00 out of 5
[?]

Adding Groups Through PowerShell

April 15th, 2009 Niklas Goude 1 comment

With our Users and Computers in place, we can start adding groups. The groups will be based on the Postition ocf the characters in the StarTrek Csv file. I’ve chosen position since many characters can have the same position.

First, let’s look at all the unique Positions in the Csv file. I’m also using the Series as a Descrption and it’s also used to place the group in the correct OU.


PS > $CsvFile | Select Position, Series -Unique


Position                     Series
--------                     ------
Commanding Officer           Star Trek: The Next Generation
First Officer                Star Trek: The Next Generation
Chief Engineer               Star Trek: The Next Generation
Chief of Security            Star Trek: The Next Generation
Chief Medical Officer        Star Trek: The Next Generation
Ship's Counselor             Star Trek: The Next Generation
Chief Operations             Star Trek: The Next Generation
Conn Officer                 Star Trek: The Next Generation
Transporter Officer          Star Trek: The Next Generation
Botanist                     Star Trek: The Next Generation
Nurse                        Star Trek: The Next Generation
Bartender                    Star Trek: The Next Generation
Engineering Officer          Star Trek: The Next Generation
Federation Ambassador        Star Trek: The Next Generation
Security Officer             Star Trek: The Next Generation
Medical Officer              Star Trek: The Next Generation
Operations Officer           Star Trek: The Next Generation
Commanding Officer           Star Trek: Deep Space Nine
First Officer                Star Trek: Deep Space Nine
Chief of Security            Star Trek: Deep Space Nine
Chief Medical Officer        Star Trek: Deep Space Nine
Chief Science Officer        Star Trek: Deep Space Nine
Counselor                    Star Trek: Deep Space Nine
Strategic Operations Officer Star Trek: Deep Space Nine
Chief Operations             Star Trek: Deep Space Nine
Civilian                     Star Trek: Deep Space Nine
Bartender                    Star Trek: Deep Space Nine
Commanding Officer           Star Trek: Voyager
First Officer                Star Trek: Voyager
Second Officer               Star Trek: Voyager
Chief Engineer               Star Trek: Voyager
Medical Officer              Star Trek: Voyager
Chief Operations Officer     Star Trek: Voyager
Chief Medical Officer        Star Trek: Voyager
Chef                         Star Trek: Voyager
Aeroponics caretaker         Star Trek: Voyager
Miscellaneous                Star Trek: Voyager
Conn Officer                 Star Trek: Voyager
Science                      Star Trek: Voyager
Engineering Officer          Star Trek: Voyager
Civilian                     Star Trek: Voyager
Commanding Officer           Star Trek: Enterprise
First Officer                Star Trek: Enterprise
Armory Officer               Star Trek: Enterprise
Engineering Officer          Star Trek: Enterprise
Medical Officer              Star Trek: Enterprise
Communications Officer       Star Trek: Enterprise
Chief Engineer               Star Trek: Enterprise

I’m going to use the first entry “Commanding Officer” to explain how the script works. At first, we have to check if the group already exists. we’ll reuse the checker function that I’ve mentioned in previous blog posts.


function Check-distinguishedName ([string]$Domain, [string]$Group) {

   trap {  $Script:distinguishedNameDoesntExist = $True ; continue }
   .Get-AD.ps1 -Domain $Domain -Group $Group -filter distinguishedName | Out-Null
}

Next we have to build up the groups distinguishedName in order to check it.


PS > $Domain = "powershell.nu"
PS > $Position = "Commanding Officer"
PS > $Series = "Star Trek: The Next Generation"
PS > $distinguishedName = "CN=" + $Position + ",OU=Groups,OU=" + $Series +
>> $Series + ($Domain.Replace(".",",DC=")).Insert(0,",DC=")
PS > $distinguishedName

CN=Commanding Officer,OU=Groups,OU=Star Trek: The Next Generation,DC=powershell,DC=nu

Now that we’ve built up a distinguishedName we can check it through the Check-distinguishedName function. If the group doens’t exist, the variable $distinguishedNameDoesntExist is set to $True, which means that we can go ahead and create the group.


PS > Check-distinguishedName $Domain $distinguishedName
PS > $distinguishedNameDoesntExist

True

Now that we’re sure that the group does’t exist we can create a connection to Active-Directory and create the group. First we’ll set up the connectionstring to the correct OU and create a [adsi] connection.


PS > $Connection = "LDAP://OU=Groups" + $Series.Insert(0,",OU=") +
>> ($Domain.Replace(".",",DC=")).Insert(0,",DC=")
PS > $AD = [adsi] $Connection

Adding the group is quite simple using the Create() method.


PS > $Group = $AD.Create("Group", "CN=$Position")
PS > $Group.SetInfo()

The part that’s not so simple is adding a unique sAMAccountName. Since there’s One Commanding officer for each ship, we will have a total of four different groups with the same name, the distinguishedName doesnt have to be unique as long as its not in the same OU but the sAMAccountName has to be.

First we have to create a sAMAccountName for the group. Since the Group names tend to be quite long, we’ll shorten the groups sAMAccountName through the subString() method if it’s longer than 10 characters. We’ll also remove spaces in the string.


PS > $sAMAccountName = ($Position.replace(" ","")).ToUpper()

PS > if ($sAMAccountName.Length -gt 10) {
  $sAMAccountName = $sAMAccountName.SubString(0,9)
}
PS > $sAMAccountName

COMMANDIN

Now that we have a sAMAccountName, we have to check so that it doesn’t exist. again through a checker function.


function Check-sAMAccountName ([string]$Domain, [string]$Group) {

  trap {  $Script:sAMAccountNameDoesntExist = $True ; continue }
  .Get-AD.ps1 -Domain $Domain -Group $Group -filter sAMAccountName | Out-Null
}

If the sAMAccountName exists, we will handle this through a while loop and append an integer at the end.


While ($Script:sAMAccountNameDoesntExist -eq $False) {

   $LastChar = $sAMAccountName.SubString($sAMAccountName.Length -1)

   if(1..9 -Contains $LastChar) {

    $sAMAccountName = ($sAMAccountName.TrimEnd([string]$LastChar)) +
    ([int]$LastChar + 1)
   } else {

    $sAMAccountName = $sAMAccountName + 1
   }

   Check-sAMAccountName -Domain $Domain -Group $sAMAccountName
}

Finally, we can add the additional group information, in this case: sAMAccountName and Description.


$Group.put("Description", $Position)
$Group.put("sAMAccountName", $sAMAccountName)
$Group.setinfo()

Here’s how it looks if we run it in our test environment.

add-stgroup01

Repeating the script shows that the groups already exist.

add-stgroup02

and here’s a quick look in dsa.msc

add-stgroup03

Additionally, let’s look at our Commanding Officer groups. We can do this through the Get-AD.ps1 script


PS > .Get-AD.ps1 -Domain powershell.nu -Group AllGroups -Property sAMAccountName, cn |
>> Where { $_.cn -match "Commanding Officer" }


sAMAccountName cn
-------------- --
COMMANDIN      Commanding Officer
COMMANDIN1     Commanding Officer
COMMANDIN2     Commanding Officer
COMMANDIN3     Commanding Officer

Isn’t it cool how you can take the result of a script and pipe it to the Where-Object CmdLet.

Click Here to Download the Complete Script.

The Get-AD.ps1 script is also required.

Click here to download the Csv File

Rating 3.00 out of 5
[?]

Adding Computers through PowerShell

April 13th, 2009 Niklas Goude 2 comments

Now let’s add a couple of computers to our test environment. The Computer Names are based on the Starships from the Csv file. Since there are alot of characters but not that many different ships we need to get a unique list of ships. We also wnat the Series, Location and Registry values.


PS > $CsvFile = Import-Csv StarTrek.csv
PS > $CsvFile | Select Series, Starship, Location, Registry -unique | fl


Series   : Star Trek: The Next Generation
Starship : USS Enterprise (NCC-1701-D)
Location : Alpha Quadrant
Registry : NCC-1701-D

Series   : Star Trek: Deep Space Nine
Starship : Deep Space Nine
Location : Alpha Quadrant
Registry : DS9

Series   : Star Trek: Voyager
Starship : USS Voyager (NCC-74656)
Location : Delta Quadrant
Registry : NCC-74656

Series   : Star Trek: Enterprise
Starship : Enterprise (NX-01)
Location : Alpha Quadrant
Registry : NX-01

Let’s walk through how the script handles the first Starship. At first we have to check if the Computer exists, We’ll use a checker function that checks if the Computer doesn’t exist.


function Check-distinguishedName ([string]$Domain, [string]$Computer) {

   trap {  $Script:distinguishedNameDoesntExist = $True ; continue }
   .Get-AD.ps1 -Domain $Domain -Computer $Computer -filter distinguishedName | Out-Null
}

Next we have to check create a variable holding a distinguishedName and check if it exists or not.


PS > $Starship = "USS Enterprise (NCC-1701-D)"
PS > $Domain = "powershell.nu"
PS > $distinguishedName = "CN=" + $Starship + ",OU=Computers,OU=" + $Series + ($Domain.Replace(".",",DC=")).Insert(0,",DC=")

Now we can run the function.


PS > Check-distinguishedName -Domain $Domain -Computer $distinguishedName

Now that we’ve checked the distinguisehdName we can connect to AD and start adding our Computer.


PS > $Connection = "LDAP://OU=Computers" + $Series.Insert(0,",OU=") + ($Domain.Replace(".",",DC=")).Insert(0,",DC=")

PS > $AD = [adsi] $Connection

PS > $Computer = $AD.Create("Computer", "CN=$Starship")
PS > $Computer.SetInfo()

Now for the additional information. We might want to change the sAMAccountName from the default name generated by AD. We also want to check that the name we choose doesn’t exist so we’ll use yet another check function.


function Check-sAMAccountName ([string]$Domain, [string]$Computer) {

   trap {  $Script:sAMAccountNameDoesntExist = $True ; continue }
   .Get-AD.ps1 -Domain $Domain -Computer $Computer -filter sAMAccountName | Out-Null
}

We’ll base the sAMAccountName on the Ships Registry information. In this case, the registry is NCC-1701-D


PS > $sAMAccountName = ($Registry).ToUpper()

PS > Check-sAMAccountName -Domain $Domain -Computer $sAMAccountName

If the sAMAccountName doesn’t exist the script will use it on the Computer object. If it does exist, theres a while loop that loops through and appends a digit in order to get a unique sAMAccountName. Here’s an example on the where loop.


While ($Script:sAMAccountNameDoesntExist -eq $False) {

   # Create New sAMAccountName

   $LastChar = $sAMAccountName.SubString($sAMAccountName.Length -1)

    if(1..9 -Contains $LastChar) {

    $sAMAccountName = $sAMAccountName.SubString(0,$sAMAccountName.Length -1) + ([int]$LastChar + 1)

   } else {

    $sAMAccountName = $sAMAccountName.SubString(0,$sAMAccountName.Length -1) + 1
   }

   Check-sAMAccountName -Domain $Domain -Computer $sAMAccountName
}

The final Steps of the script add the additional information and enables the computer.


PS > $Computer.put("sAMAccountName", $sAMAccountName)
PS > $Computer.put("Location", $Location)
PS > $Computer.put("Description", $Starship)
PS > $Computer.setinfo()

PS > $Computer.PsBase.InvokeSet("AccountDisabled", $False)
PS > $Computer.SetInfo()

Now let’s run the script in our test environment.

add-stcomputer011

If we repeat the script it’ll tell us that the computers already exist.

add-stcomputer02

If we check in dsa.msc snap-in we can see that the computer objects have been created.

add-stcomputer03

and finally, if we want to retrieve the information through PowerShell, we can use the Get-AD.ps1 script.


PS > .Get-AD.ps1 -Domain powershell.nu -Computer "Uss Enterprise (NCC-1701-D)"


objectClass          : top person organizationalPerson user computer
cn                   : USS Enterprise (NCC-1701-D)
description          : USS Enterprise (NCC-1701-D)
distinguishedName    : CN=USS Enterprise (NCC-1701-D),OU=Computers,OU=Star Trek
                       u
instanceType         : 4
whenCreated          : 4/13/2009 7:19:11 PM
whenChanged          : 4/13/2009 7:19:11 PM
uSNCreated           : System.__ComObject
uSNChanged           : System.__ComObject
name                 : USS Enterprise (NCC-1701-D)
objectGUID           : 31 54 123 251 207 232 62 72 153 101 238 77 71 88 19 27
userAccountControl   : 544
badPwdCount          : 0
codePage             : 0
countryCode          : 0
badPasswordTime      : System.__ComObject
lastLogoff           : System.__ComObject
lastLogon            : System.__ComObject
pwdLastSet           : System.__ComObject
primaryGroupID       : 513
objectSid            : 1 5 0 0 0 0 0 5 21 0 0 0 50 71 101 4 93 25 58 165 36 24
accountExpires       : System.__ComObject
logonCount           : 0
sAMAccountName       : NCC-1701-D
location             : Alpha Quadrant
sAMAccountType       : 805306368
objectCategory       : CN=Computer,CN=Schema,CN=Configuration,DC=powershell,DC=
nTSecurityDescriptor : System.__ComObject

Click Here to Download the Complete Script.

The Get-AD.ps1 script is also required.

Click here to download the Csv File

Rating 3.00 out of 5
[?]

Adding Users through PowerShell

April 13th, 2009 Niklas Goude 2 comments

Now that we have our OU structure in place, we can start adding users.

Since the Users contain alot of information we’ll go ahead and use the whole csv file.

Let’s take a quick look at the first entry in the Csv file:


PS > (Import-Csv StarTrek.csv)[0]


Character  : Jean-Luc Picard
Position   : Commanding Officer
Rank       : Captain
Department : Main Bridge
Species    : Human
Starship   : USS Enterprise (NCC-1701-D)
Class      : Galaxy
Registry   : NCC-1701-D
Series     : Star Trek: The Next Generation
Location   : Alpha Quadrant

Let’s start adding the Users to the Domain. First off, we need to build up a connectionstring. In the script, I build it based on


PS > $Series = "Star Trek: The Next Generation"
PS > $Domain = "powershell.nu"
PS > $Connection = $Series.Insert(0,"LDAP://OU=Users,OU=") + ($Domain.Replace(".",",DC=")).Insert(0,",DC=")
PS > $Connection

LDAP://OU=Users,OU=Star Trek: The Next Generation,DC=powershell,DC=nu

Now for the Fun part. In the Csv file, some Characters don’t have any surNames and some have middle names, so this is something I have to consider in the script. Thanks to the Power of PowerShell it doesn’t have to get to complex.

Step one is Checking the characters name. I use the Split() method to determine if the user has a SurName or any Middle Names.


PS > $Character = "Jean-Luc Picard"
PS > $CharacterName = $Character.Split(" ")
PS > $CharacterName

Jean-Luc
Picard

In this example, Jean-Luc would be the givenName and Picard the surName. I control this in the script through a if else statement that checks if the $CharacterName contains 1 row or more.


if (($CharacterName.Count) -le 1) {

} else {

}

In the case of Jean-Luc Picard, the Name contains more than 1 row, so let’s move on to the else statement.

The else statement starts of by setting up giveName and SurName. the $giveName variable contain all names except the last one. So if we would use Charles Trip Tucker instead of Picard, the givenName would be “Charles Trip” and surName would be set to “Tucker”.


PS > $givenName = $CharacterName[0..($CharacterName.Count -2)]
PS > $sn = $CharacterName[($CharacterName.Count -1)]
PS > $givenName

Jean-Luc

PS > $sn

Picard

Now that we’ve sliced and diced the characters name, we do an additional check to see if the character name will fit the sAMAccountName structure decided in Part 1.0.0 (First 3 from giveName and first 3 from surName).


if ($givenName.Length -lt 3 -AND $sn.Length -lt 3) {

   $Tempcn = $givenName + $sn
   $AddNum = 3 - $Tempcn.Length

   # Build Last Part Of cn

   for ($i = 0; $i -lt ($AddNum -1); $i ++) { $AddTocn += "0" }
   $AddTocn += "1"

   [string]$sAMAccountName = ($Tempcn).ToLower() + $Addtocn
   $cn = $givenName

   # Set Checker to Null

   $AddTocn = $Null

} elseif ($givenName.Length -lt 3 -OR $sn.Length -lt 3) {

   $Tempcn = $givenName + $sn

   [string]$sAMAccountName = ($Tempcn.SubString(0,6)).ToLower()
   $cn = $givenName + " " + $sn

} else {

   [string]$sAMAccountName = ($givenName.SubString(0,3)).ToLower() + ($sn.SubString(0,3)).ToLower()
   $cn = $givenName + " " + $sn
}

The if elseif else statement goes through the characters name and checks if it falls within parameters. If it does not, a number will be added at the end of the Name to compensate. The elseif statement takes care of users where givenName or surName has less than 3 characters and compensates this.

Here’s how Jean-Luc Picard is set up now:


PS > $givenName

Jean-Luc

PS > $sn

Picard

PS > $sAMAccountName

jeapic

PS > $cn

Jean-Luc Picard

Now that we have the sAMAccountName in place we have to check if the sAMAccountName is taken by some other User. We can do this by creating a function that looks up the users sAMAccountName from the Get-AD.ps1 script.


function Check-sAMAccountName ([string]$Domain, [string]$User) {

   trap {  $Script:sAMAccountNameDoesntExist = $True ; continue }
   .Get-AD.ps1 -Domain $Domain -User $User -Filter sAMAccountName | Out-Null
}

If the UserName already exists the script uses a While loop to determine how many sAMAccountNames are taken and when an empty sAMAccountName is found it will be used.


if ($sAMAccountNameDoesntExist -eq $True) {

} else {

   While ($Script:sAMAccountNameDoesntExist -eq $False) {

    $LastChar = $sAMAccountName.SubString($sAMAccountName.Length -1)

    if(1..9 -Contains $LastChar) {

       $sAMAccountName = ($sAMAccountName.TrimEnd([string]$LastChar)) + ([int]$LastChar + 1)
    } else {

       $sAMAccountName = $sAMAccountName + 1
    }

    Check-sAMAccountName -Domain $Domain -User $sAMAccountName
   }
}

If jeapic already exists the number 1 will be appended to his sAMAccountName, and if jeapic1 already exists 1+1 ( 2) would be appended instead. Note that doing this sets the sAMAccountName to 7 characters instead of 6. If you always want to use 6 chars you could substring() out characters 1 to 5 ( 0,4 ) and build up a sAMAccountName containing only 6 characters.

Now that we have a unique sAMAccountName, we want to check the Users distinguishedName. If the distinguishedName already exists then we will not Add the User, since he already exists. If not, we will go ahead and add our user. The distinguishedName check function is basically the same as the sAMAccountName checker, only differens is that it filters on distinguishedName instead.


function Check-distinguishedName ([string]$Domain, [string]$User) {
   trap {  $Script:distinguishedNameDoesntExist = $True ; continue }
   .Get-AD.ps1 -Domain $Domain -User $User -filter distinguishedName | Out-Null
}

The function takes distinguishedName as an argument, so we have to build up this string. The OU structure was set up in Part 1.1.1 so the User should be in the following OU: “OU=Users,OU=Star Trek: The Next Generation,DC=powershell,DC=nu”.


$distinguishedName = "CN=" + $cn + ",OU=Users,OU=" + $Series + ($Domain.Replace(".",",DC=")).Insert(0,",DC=")

If the disyinguishedName doesnt exist, we can go ahead and create the User. For safety reasons, we generate a secure password for each user that we create and store the passwords in a password file. We could obviously set all Passwords to “Password1″ but that wouldn’t be fun.

Here’s a simple password generator that I’ve created. Using the System.Random Class to generate random numbers.


function Generate-Password {

  $Random = New-Object System.Random

  # Two Upper Case Characters

  [string]$Password += [char]$Random.Next(49,57)
  [string]$Password += [char]$Random.Next(65,72)

  # Two LowerCase Characters

  [string]$Password += [char]$Random.Next(97,107)
  [string]$Password += [char]$Random.Next(109,122)

  # One Special Char

  [string]$Password += [char]$Random.Next(36,43)

  # Two UpperCase Characters

  [string]$Password += [char]$Random.Next(65,72)
  [string]$Password += [char]$Random.Next(80,91)

  # One LowerCase

  [string]$Password += [char]$Random.Next(97,107)

  $Password
  $Password = $Null
}

Why not make it a a shorter script and randomize [char]49 to [char]122? Well, if I randomize any character from [char]49 to [char]122 i might get an “O” and numeric “0″, or “l”,”I” or numeric “1″. Users might find it hard to differentiate an O from an 0 so I’ve excluded Characters that look alike in the function. Also, if I use a for statement and loop through [char]$Random.Next(49,122) eight times, it’s not certain that i get an acceptable Password, i might all uppercase characters and AD wouldn’t accept that.

Now that we have a Password generator we can create our User.


PS > $Description = $Position + " (" + $Species + ")"
PS > $Title = $Rank
PS > $physicalDeliveryOfficeName = $Starship
PS > $userPrincipalName = $sAMAccountName + "@" + $Domain
PS > $mail = ([string]$Character).Replace(" ",".") + "@" + $Domain

PS > [string]$Password = Generate-Password

PS > $OU = [adsi] $Connection
PS > $User = $OU.Create("user", "cn=$cn")
PS > $User.Put("sAMAccountName", $sAMAccountName)
PS > $User.Put("userPrincipalName", $userPrincipalName)
PS > $User.Put("DisplayName", $cn)
PS > $User.Put("givenName", $givenName)
PS > $User.Put("sn", $sn)
PS > $User.Put("Description", $Description)
PS > $User.Put("l", $Starship)
PS > $User.Put("streetAddress",$Location)
PS > $User.Put("physicalDeliveryOfficeName", $physicalDeliveryOfficeName)
PS > $User.Put("Title", $Title)
PS > $User.Put("Department", $Department)
PS > $User.Put("Company", $Starship)
PS > $User.Put("mail", $mail)
PS > $User.SetInfo()

PS > $User.PsBase.Invoke("SetPassword", $Password)
PS > $User.PsBase.InvokeSet("AccountDisabled", $false)
PS > $User.SetInfo()

Now all i have to do is Collect the Generated Password in a file.


PS > $FileName = "PasswordList " + (get-date -uformat "%Y-%m-%d") + ".txt"
PS > "$sAMAccountName,$cn,$Password" | Add-Content $FileName

Running the script in our test environment would look something like this:

add-stuser01

If we repeat the script, the checker function fould tell us that the Users already exist:

add-stuser02

Now for a peek in Active-Directory snap-in dsa.msc

add-stuser03

And Finally, let’s look closer on Captain Jean-Luc Picard and see if the Values specified in the script are set.

add-stuser04

And here’s an example on the Autogenerated Password List.

Click Here to Download the Complete Script.

The Get-AD.ps1 script is also required.

Click here to download the Csv File

Rating 3.00 out of 5
[?]

Adding Ou Structure using Powershell

April 13th, 2009 Niklas Goude No comments

Starting of, we need to set up a couple of OrganizationalUnits in our test environment. Following the structure set up in Part 1.1.0:

Organizational Unit Structure

  • ou = Series
  • l = Location
  • Description = Starship
  • Child OU: Computers
  • Child OU: Groups
  • Child OU: Users

The first step in scripting up a OU structure from based on the StarTrek Csv file is to collect the information through PowerShell. Since the Csv file contains 68 rows of information and 10 different columns, we want to retrieve only information that we need to create a Csv Structure. The columns of interest are: Series, Starship and Location. Using Import-Csv in combination With Select-Object gets all entries matching this.


PS > Import-Csv StarTrek.csv | Select-Object Series, Starship, Location


Series                         Starship                    Location
------                         --------                    --------
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant

Now we,ve managed to retrieve the specified columns and rows. Next we need to narrrow the list down to only unique entries. We can achieve this through the -Unique SwitchParameter.


PS > Import-Csv .StarTrek.csv | Select-Object Series, Starship, Location -Unique


Series                         Starship                    Location
------                         --------                    --------
Star Trek: The Next Generation USS Enterprise (NCC-1701-D) Alpha Quadrant
Star Trek: Deep Space Nine     Deep Space Nine             Alpha Quadrant
Star Trek: Voyager             USS Voyager (NCC-74656)     Delta Quadrant
Star Trek: Enterprise          Enterprise (NX-01)          Alpha Quadrant

Now that we’ve narrowed down our list, we can start creating the OU structure.

The OU:s Name should be “Series”, so the structure that we’re looking for is:

  • Star Trek: The Next Generation
  • Star Trek: Deep Space Nine
  • Star Trek: Voyager
  • Star Trek: Enterprise

But how do we know that these OU:s dont already exist in our Environment ? We have to check this in some way so we need a checker that makes sure that the OU doesn’t exist. This is an excellent oppurtunity to use the Get-AD.ps1 script that I wrote. The checker is rather simple, it consists of a function that sets a variable to $True if the OU does not exist.


function Check-distinguishedName ([string]$Domain, [string]$OU) {

	trap {  $Script:distinguishedNameDoesntExist = $True ; continue }
	.\Get-AD.ps1 -Domain $Domain -OU $OU -Filter distinguishedName | Out-Null
}

The Variable $Script:distinguishedNameDoesntExist is set to $True if we test the function on a non existing OU. Here’s an example on how it works:


PS > Check-distinguishedName -Domain powershell.nu -OU "OU=Domain Controllers,DC=powershell,DC=nu"
PS > $distinguishedNameDoesntExist

Since Domain Controllers Exist, the variable $distinguishedNameDoesntExist is not set to anything. Running the same function on a OU that does not exist:


PS > Check-distinguishedName -Domain powershell.nu -OU "OU=Non Existing OU,DC=powershell,DC=nu"
PS > $distinguishedNameDoesntExist

True


PS > $distinguishedNameDoesntExist = $Null

This time the variable $distinguishedNameDoesntExist was set to True, which means that the OU does not exist and it’s available for creation. I also set the Variable to $Null so that i can reuse the function.

Moving on. If the $distinguishedNameDoesntExist equals $True we can start building up the OU Structure. In the script, there’s a paramter called -Domain which takes the domain name as an argument. In my examples I’m going to use the powershell.nu domain. Setting this as an argument is similar to creating a Variable holding the domain name:


PS > $Domain = "powershell.nu
PS > $Domain

powershell.nu

With this information we can create a Connection string that we can use when connecting to Active-Directory. We can make use of the methods() withing System.String to alter the string as we want it. I’m using Replace() and Insert() to get the result I want:


PS > $Connection = ($Domain.Replace(".",",DC=")).Insert(0,"LDAP://DC=")

PS > $AD = [adsi] $Connection
PS > $AD


distinguishedName
-----------------
{DC=powershell,DC=nu}

Now that we’ve set up a connection we can start creating an OU. It’s pretty straight forward, nothing fancy here:


PS > $OU = $AD.Create("OrganizationalUnit", "ou=$Series")
PS > $OU.SetInfo()

PS > $OU.put("l", $Location)
PS > $OU.put("Description", $Starship)
PS > $OU.setinfo()

When creating Child OU:s, we need to alter the Connection string so that we connect to the OU that we’ve just created, here’s an example on doing that:


$NewConnection = "LDAP://OU=" + $Series + ($Domain.Replace(".",",DC=")).Insert(0,",DC=")
$NewOU = [adsi]$NewConnection

Now we can start creating Child OU:s that are structured after our purpose:


$Users = $NewOU.Create("OrganizationalUnit", "ou=Users")
$Users.SetInfo()

$Users.put("l", $Location)
$Users.put("Description", $Starship)
$Users.setinfo()

This describes the steps that I’ve set up in the Script. Running the script in the test environment would look like this:

add-stou01

If i repeat the script, the Check function finds that the top OU:s already exists and the following is returned to the host:

add-stou02

Finally, taking a peek in dsa.msc.

add-stou03

Click Here to Download the Complete Script.

The Get-AD.ps1 script is also required.

Click here to download the Csv File

Rating 3.00 out of 5
[?]