Powershell

7Zip with Powershell

7-Zip is something I use on a daily basis not only for creating or extracting various archive formats but for extracting ISOs. I love this feature of 7-Zip.

Something I’ve wanted to do for a while was figure out if it was possible to use 7-Zip from Powershell and indeed it is.

There is a C# wrapper for 7-Zip available at http://sevenzipsharp.codeplex.com/ that makes this all a lot easier. You’ll need to download the SevenZipSharp.dll as well as the native 7-Zip dlls (they’re in the Other Available Downloads section).

I’ve extracted SevenZipSharp.dll, 7z.dll and 7z64.dll to a directory called SevenZipSharp.

First up you’ll need to load the Assembly:

1
Add-Type -Path "D:\Tools\Assemblies\SevenZipSharp\SevenZipSharp.dll"

Then simply create an extractor and extract the archive, simply:

1
2
$extractor = New-Object SevenZip.SevenZipExtractor('D:\Data\BigArchive.zip')
$extractor.ExtractArchive('D:\tmp')

Note for x64 users
When I first tried this I got an error when attempting to create an SevenZip.SevenZipExtractor object: New-Object : Exception calling “.ctor” with “1″ argument(s): “Can not load 7-zip library or internal COM error! Message: failed to load library.”

This is because the SevenZipSharp.dll looks for 7z.dll in the same directory and the 7z.dll in that directory is the x86 Dll. You have two options, rename 7z64.dll to 7z.dll or run the following after loading the assembly:

1
[SevenZip.SevenZipExtractor]::SetLibraryPath('D:\Tools\Assemblies\SevenZipSharp\7z64.dll')
Read more

Editing Powershell in Visual Studio

Looking for Powershell support in Visual Studio 2010?? Check out PowerGUI VSX! Essentially you get the great features of PowerGUI inside the Visual Studio IDE. Well worth downloading.

Read more

Powershell Prompt

Customising my Powershell prompt was something that I never really thought I’d do. After all surely the out of the box prompt tells me where I am and making a new one seems like a bit of work. Well actually it’s not and I kept getting my x86 and x68, admin and non-admin prompts confused. So I altered my prompt to inlucde this information.

Firstly, to change your prompt you just need to write your own prompt function as this is what generates the prompt each time the prompt is printed to the screen. To see the default promtp try the following:

1
(Get-Item Function:\prompt).Definition

You’ll get back something like this:

1
2
$(if (test-path variable:/PSDebugContext) { '[DBG]: ' } else { '' }) + 'PS ' +
$(Get-Location) + $(if ($nestedpromptlevel -ge 1) { '>>' }) + '> '

So the first thing that I wanted to change was adding [Admin] in red to the start of the prompt if I’m running as an administrator. I have a global variable in my profile called $IsAdmin that tells me if I’m an admin or not. So the code below uses write-host to output ‘[Admin]‘ in red if I’m an Administrator.

1
2
3
4
if( ([System.Environment]::OSVersion.Version.Major -gt 5) -and ($IsAdmin) )
{
write-host '[Admin]' -NoNewLine -Fore 'red'
}

Next, I wanted to show if I was running x86 or x64. Which simply involved creating a string with the right architecture type and adding that to the prompt.

1
2
3
4
5
6
7
$bitness = ''
if ([IntPtr]::Size -eq <img src="https://web.archive.org/web/20120320084139im_/https://www.project84.net/wp-includes/images/smilies/icon_cool.gif" alt="8)" class="wp-smiley"> {
$bitness = '(x64)'
}
elseif ($Pscx:IsWow64Process) {
$bitness = '(x86)'
}

I added a few other bits but here’s the end result:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
## Set My Prompt
## . Set-Prompt.ps1 in profile.
function prompt {
## If this is Vista or higher and we're an admin change the prompt
$adminPrompt=''
if( ([System.Environment]::OSVersion.Version.Major -gt 5) -and ($IsAdmin) )
{
#$adminPrompt='[Admin]'
write-host '[Admin]' -NoNewLine -Fore 'red'
}
## Get the commmand ID for Get-History/Invoke-History
$nextCommandId = (Get-History -count 1).Id + 1
#was there an error in the last thing we did??
$err = !$?
#Totally stole this from somewhere, finds the architecture
$bitness = ''
if ([IntPtr]::Size -eq <img src="https://web.archive.org/web/20120320084139im_/https://www.project84.net/wp-includes/images/smilies/icon_cool.gif" alt="8)" class="wp-smiley"> {
$bitness = '(x64)'
}
elseif ($Pscx:IsWow64Process) {
$bitness = '(x86)'
}
if($err) { $fg = "Red" } else { $fg = "Cyan" }
write-host "PS$bitness [$nextCommandId]$(Get-Location)>" -NoNewLine -Fore $fg
return " "
}
Read more

Powershell Console Colours

I’m certain this is probably elsewhere on the web but I couldn’t find it immediately. I was wondering how to ouput the names of each console colour in the corresponding colour. Turns out it’s really easy:

1
[consolecolor]::GetNames([consolecolor]) | %{Write-Host "$_" -For $_}
Read more

Moving SCCM Packages and Drivers Source Location

I had a situation recently where a server that had the source shares for my Packages and Drivers had to be decommissioned. This initially seemed like an simple task of updating the source location in each package to the new server. However after realising that there were a lot of packages and about 400 drivers I sought a better way. Powershell to the rescue!

The following block of Powershell gets all the drivers and does a search and replace on the server name.

1
2
3
4
$drivers = Get-WmiObject SMS_Driver -Namespace root\SMS\site_LNK
$drivers | ?{$_.ContentSourcePath -like "\\creekserver\*"} | `
%{$_.ContentSourcePath = $_.ContentSourcePath -replace "creekserver", "PRI-SCCM-V01"; $_.Put()}

I did the same for packages:

1
2
3
4
5
6
$packages = Get-WmiObject SMS_Package -Namespace root\SMS\site_LNK
$packages | ?{$_.PkgSourcePath -like "*creekserver*"} | `
%{$_.PkgSourcePath = $_.PkgSourcePath -replace "creekserver","PRI-SCCM-V01"; $_.Put()}
$packages | %{$_.RefreshPkgSource}

Enjoy!

Read more

MDT 2008 and Powershell: Creating a distribution directory

I’ve been playing with automating MDT 2008 using Powershell and thought I’d start to share some of the info over the next few weeks.

The very first thing you need to do in MDT is create a Distribution Share. It turns out this is exceptionally easy in Powershell. The Microsoft.BDD.ConfigManager.Manager namespace has a method called UpgradeDistributionShare(string location, bool update). Just pass in the location you’d like to create the distribution share at and you’re done! You can set update to true if you are upgrading an existing Distribution Share to MDT 2008.

Here is the code:

1
2
3
4
5
6
7
8
9
10
11
Param
(
[string]$Location=$(throw"You must specify a Location")
)
#Initialize MDT
[System.Reflection.Assembly]::LoadFile("C:\Program Files\Microsoft Deployment Toolkit\Bin\Microsoft.BDD.ConfigManager.dll") | Out-Null
$manager= [Microsoft.BDD.ConfigManager.Manager]
#Create a new MDT Distribution Share
$manager::UpgradeDistributionShare($Location, $false)
Read more

Finding large files with Powershell

I find that my free space is one of those things I don’t check regularly enough. This morning I logged on only to find my system was really struggling. I didn’t take long to realise I only had 600MB of disk space left. Dratt!!

I immediately wondered what was the quickest way to find out where all my space went, Powershell maybe? My first thought was something like this:

get-ChildItem –path C:\ –recurse | where-Object {$_.Length -gt 50000000} | sort-Object –property length –Descending |select-Object –first 10 | format-Table Name, Length –auto

This seemed to work ok but took ages:
Days              : 0
Hours             : 0
Minutes           : 1
Seconds           : 55
Milliseconds      : 828
Ticks             : 1158286885
TotalDays         : 0.00134060982060185
TotalHours        : 0.0321746356944444
TotalMinutes      : 1.93047814166667
TotalSeconds      : 115.8286885
TotalMilliseconds : 115828.6885

Anyone know a better way??

Read more

Using PowerShell to find nested Groups for Active Directory Migration

I’ve been involved in an Active Directory Migration lately and one of the things that was taking a lot of time was finding the groups for a group of users and then finding the nested groups. Why, you might ask? Well in this particular instance it was easier for us to migrate groups first than users but we had to make sure we got all the groups for the users we wanted to migrate moved over first.

The first part of the script involves search Active Directory for the user we wish to find group membership for. This is pretty easy:
#Setup Tasks
$query = new-object system.directoryservices.directorysearcher
$root = [adsi]“”

#Setup for Query
$query.searchroot=[adsi]$(“LDAP://”+$root.distinguishedName)
$query.Filter = “(&(objectCategory=user)(objectClass=person)(samAccountName=$accountName))”
$query.SearchScope=“Subtree”

The next thing to do after we find the user is to get the memberOf Property:
$ADobject.psbase.Properties[“memberOf”]

So I found it was easy enough to get a list of groups for a user but how could a get a list for several users without getting duplicates? The logical thing seemed like a hashtable:
$groups = @{}
foreach ( $user in $users ) {
foreach ($group in Get-Groups $user)
{
$groupName=$($group.split(“,”)[0]).split(“=”)[1] if(!$groups.Contains($groupname)){$groups.Add($groupname,$group)}
}
}

The Properties[“memberOf”] returns a collection of distinguished names, (CN=GroupName,OU=Groups,DC=domain,DC=local), so the above code splits up that string to extract the groupName to be the key for the hashtable and then the DN as the value. After this it is simply a case of connecting to each group and listing the memberOf property to see if there is any nested groups.

The code will only check 1 level deep so if you have a chain of nested groups you’ll have to check it manually.

To Run the script just run .\GetGroups “username1″,”username2″,”username3″. Please let me know what you think.

FindNestedGroups.ps1.txt (.91 KB)

Read more

ShinyPower

Spotted this little utility the other day called ShinyPower and it is definately a must have for anyone learning PowerShell. It’s over at secretGeek: http://secretgeek.net/shinyPower.asp

From the site: “ShinyPower is a little C# app i wrote to automate browsing PowerShell’s help files.”

 

Read more