new-blogentry -topic "Powershell and More"

My observations about Powershell, Windows, System Center and life.

Recent comments

Tags

Don't show

    Disclaimer

    Any opinions expressed herein are completely accidental. But if one happens to slip in, it represents my own personal opinion and NO one elses. I'm also not concerned with changing anyone elses opinion, so any rants about anything presented on this site are likely to be 100% ignored.

    © Copyright 2010

    Missing 64 bit native commands in Powershell (x86)?

    For those using a x64 Windows OS, you may find that many times you still need to use the x86 version of Powershell due to snapin compatibilities. Have you ever noticed that a number of native (dos/command prompt) commands are only available as 64 bit EXEs and not immediately available from your x86 Powershell session? Some examples are nbtstat.exe, telnet.exe, tscon.exe, tsdiscon.exe, and query.exe. Somewhat annoying.

    I’m not going to go into details about all the fun of API call thunking or Windows-On-Windows (WoW), because frankly… I don’t care. I just want to run nbtstat.exe from my x86 version of Powershell!

    Fortunately, there is a way to access these elusive 64 bit EXEs. Add %systemroot%\sysnative to your PATH. Here’s a small snippet you can add to your profile.ps1 that will add this folder to the end of the path for your Powershell session.

    Version 2 Code: (see Version 1 variant below)

    if ( (Test-Path "$($env:systemroot)\sysnative") -and ($env:path -split ';' -notcontains "$($env:systemroot)\sysnative") ) { 
        $env:path = "$($env:path);$($env:systemroot)\sysnative" 
        Write-Host "Path updated to include: $($env:systemroot)\sysnative"
    } 
    

    I added in checks to make sure the sysnative exists (it won’t under a x64 process, only x86 processes) and that it’s not already in the path to avoid duplication.

    One caveat. %systemroot%\sysnative redirection only works on Vista, Windows 2008, or Windows 7. XP and 2003 are a bit in the cold on this one (although there is hotfix KB942589 to add sysnative to Windows 2003 – but I’ve not tested it).

     ** Alexandair pointed out that I used -split operator which requires Powershell v2. The following works in v1 and v2:

    if ( (Test-Path "$($env:systemroot)\sysnative") -and (($env:path).split(';') -notcontains "$($env:systemroot)\sysnative") ) {
        $env:path = "$($env:path);$($env:systemroot)\sysnative"
        Write-Host "Path updated to include: $($env:systemroot)\sysnative"
    }

    Gaurhoth


    Posted by gaurhoth on Wednesday, May 13, 2009 9:53 AM
    E-mail | Permalink | Comments (0) | Post RSSRSS comment feed

    Powershell as a 'Software Update' -ne 'Good Decision'

     

     

     

     

     

     

     

     

     

    There is a scenario that can cause a great amount of grief if you aren’t aware of it. And if you are aware of it, it can cause sleeplessness.

    I’m talking about the decision to make Powershell a ‘Software Update’, which brings along some delicate issues when you install a Service Pack after installing Powershell. Namely, the fact that you can no longer uninstall Powershell from the Control Panel. This is a design decision by Microsoft and it makes sense for most ‘true’ software updates. You wouldn’t want netapi32.dll being rolled back to an earlier version if you uninstalled a software update in the wrong order.

    I just ran into this situation in my production environment. I had a need to install Powershell on a Windows 2003 server and drafted my change management for just that. Unfortunately, I didn’t realize that this server still had SP1. If I install Powershell v1 and someone installs SP2, I’ll be unable to uninstall Powershell v1 if the need arises.

    So what do I do? Abandon discretion and install Powershell v1 knowing I could face future problems. Delay the entire project until I can install SP2? or violate custom if not law, but installing Powershell v2 CTP2 which is a standalone installer/uninstaller.

    Personally, I’d love to see Powershell *MORE* standalone in nature (even portable!), rather than subject to numerous install/uninstall concerns.

    UPDATE: Installing Powershell v2 CTP2 is not an option on Windows 2003 SP1 (it requires SP2). Now I’m well and truly stuck between a rock and a hard place. Jeffery, if you ever see this, please reconsider the update strategy! :)


    Categories: powershell
    Posted by gaurhoth on Saturday, November 08, 2008 4:29 PM
    E-mail | Permalink | Comments (24) | Post RSSRSS comment feed

    Operations Manager Command Shell

    I run Windows 2008 64bit on my main workstation, so when I installed the Operations Manager Console and Command Shell for remote administration of OpsMgr, it only added the snapin for 64bit Powershell. However, I generally use Powershell Plus (which is 32bit only), and thus couldn’t access the Operations Manager Command Shell stuff from my normal environment.

    InstallUtil didn’t work against Microsoft.EnterpriseManagement.OperationsManager.ClientShell.dll, so I resigned myself to using the native powershell console.

    Until now. By using Add-Module from Powershell v2 CTP2, I was able to load the DLL and provide access to the cmdlets for Operations Manager. I’m NOT a developer and have no idea what’s going on underneath. So here’s the script I use to initialize the Operations Manager Command Shell in my 32bit Powershell Plus environment. I’ll leave it to someone like Joel to explain just WHY this works! It’s also possible this doesn’t provide 100% functionality, but so far everything I’ve tried has worked.

    param ( $OpsmgrPath = "C:\Program Files\System Center Operations Manager 2007\", $ManagementServer = "", $SavePrompt = $true ) if (Test-Path $opsmgrpath) { if ($SavePrompt) { $pr = gc function:prompt } $shelldll = "Microsoft.EnterpriseManagement.OperationsManager.ClientShell.dll" $functionpath = "Microsoft.EnterpriseManagement.OperationsManager.ClientShell.Functions.ps1" Add-Module $(Join-Path $opsmgrpath $shelldll) &$(Join-Path $opsmgrpath $functionpath) Start-OperationsManagerClientShell -ManagementServerName: $ManagementServer -PersistConnection: $true -Interactive: $true; if ($SavePrompt) { $pr | sc function:prompt } } else { Write-Host -foregroundcolor yellow "Unable to find the Operations Manager Install Directory. Pass the correct Install Direcotry with the -OpsmgrPath argument." }

    Posted by gaurhoth on Sunday, September 28, 2008 12:32 PM
    E-mail | Permalink | Comments (36) | Post RSSRSS comment feed

    Micro-Rant: SCOM's Criteria Expression Syntax

    In SCOM (System Center Operations Manager 2007) related powershell cmdlets, there is a parameter to specify a search criteria. My rant involves the fact that the syntax for it doesn’t match Powershell’s comparison operators at all :(

    I’m sure there are very good reasons (the underlying SDK was probably designed long before powershell support was decided on), but it’s still frustrating to learn a different syntax for each tool (such as WMI, which has it’s own syntax. Admittedly, WMI predates Powershell by a LONG time.

    Ah well.

     

    * Apologies if this is a duplicate in anyone’s RSS feed. An issue with my web host provider caused the removal of my site's content. My latest backup was prior to this post.


    Posted by gaurhoth on Thursday, July 24, 2008 3:49 PM
    E-mail | Permalink | Comments (39) | Post RSSRSS comment feed

    Ripping CDs with Powershell

    Reading books is one of my favorite past times, but since I have 4 kids and an insane job… I settle for listening to them as audiobooks. I wanted to rip some Audiobook CD’s to WMA for playing on  my Sansa Fuze and I wanted to tinker with automating Windows Media Encoder. Combine all that with some perverse pleasure in doing almost anything in powershell and you have the following script.

    I couldn’t find a .NET class for ripping audio from CDs, but I did find BonkEnc that has a command line executable which I could conveniently automate from powershell. You should download the plain zip package of BonkEnc from http://www.bonkenc.org and extract the contents to a subfolder of your Module Root.

    Using BonkEnc to end up with a folder full of WAV files from the CD was relatively easy. Trying to script the Windows Media Encoder was an exercise in pure brute force. I took every vbscript example I could find and attempted to port to Powershell, which I finally managed; but it may not be entirely pretty. You be the judge.

    I’ve been using this script as a dot-sourced PS1 for a few weeks now, but due to the dependency on 2 third party components (bonkenc and taglib-sharp) – finding a way to make it portable for posting online was frustrating me. I had too many hard coded paths. So I used this as an excuse to play with Modules in CTP2. As such the script presented does require CTP2.

    You’ll need to download Taglib-Sharp from http://www.taglib-sharp.com/Download/ and place the taglib-sharp.dll in your Module Root folder or a subfolder.

    And finally, be sure you download and install the 32bit version of Windows Media Encoder from http://www.microsoft.com/downloads/details.aspx?FamilyID=5691ba02-e496-465a-bba9-b2f1182cdf24&displaylang=en. If you are using Vista, be sure to visit http://support.microsoft.com/default.aspx/kb/929182 for a hotfix.

    Create a folder named “Packages” under your “WindowsPowershell” folder (in your “Documents” or “My Documents” folder). Next create a folder named “Rip-Audiobook” under the newly created Packages folder and drop the Rip-Audiobook.psm1 file into it. This is your Module Root folder. Drop BonkEnc and Taglib-sharp in this folder (or subfolder) and execute the following line in powershell:

    45# add-module Rip-Audiobook
    

    Insert the Audiobook CD and execute the following:

    48# Rip-Audiobook
    

    Follow the prompts and enter requested information so the resultant WMA file will be properly Tagged. Tag information is saved in an XML file for the next time you run Rip-Audiobook. You can just press ENTER to avoid reentering information that hasn’t changed.

    Answer the following configuration questions (Pressing ENTER will use the default value shown).  
    Destination Folder (C:\Users\gaurhoth\music):                                                   
    Title (The Fires of Heaven):                                                                     
    Author (Robert Jordan):                                                                          
    Series (Wheel of Time, Book 05):                                                                 
    CD Number (2):                                                                                   
    

    You’ll be prompted when everything is completed and you should find your WMA file where ever you specified for the ‘Destination Folder’.

    Here’s the Code (There’s a link to download the PSM1 file at the bottom of this post).

    function Start-Process {
    # Allows us to start the process with -elevated switch
    # to accomodate Vista. You'll be prompted for elevation
    # if you don't run powershell elevated.
        param ($apppath, [switch]$elevated)
        $se = new-object "System.Diagnostics.ProcessStartInfo"
        $se.UseShellExecute = $FALSE
        if ($elevated) { $se.Verb = "runas" }
        $se.RedirectStandardOutput = $TRUE

        $se.FileName = $apppath
        $se.Arguments = [string]$Args

        [System.Diagnostics.Process]::Start($se)
    }

    function New-TempFolder {
        # Prepare new temporary folder
        do {
            $temp = [io.path]::GetTempPath() + [io.path]::GetRandomFileName()
        } while ( $temp | Test-Path )
        mkdir $temp
    }

    function Encode-Audio {
        param (
            [string]$destination,
            [IO.FileInfo[]]$SourceFiles,
            $Profile = 'Windows Media Audio 8 for Dial-up Modem (CD quality, 64 Kbps)'
        )

    Write-Host @'
    ______________________________________________________________
    /  Encode-Audio:
    |    by Gaurhoth (http://www.skyeagle.net/blog)
    |  
    |  This script encodes a set of source WAV files to a single WMA.
    |  
    |  Example Usage:
    |    Encode-Audio -destination "$home\Music\Encoded-Audio.WMA" `
    |           -SourceFiles $("$home\music\WAVDIR\" | dir | sort)
    |    
    |  Requirements:
    |    Windows Media Encoder 9 (32bit tested)
    |       http://www.microsoft.com/downloads/details.aspx?FamilyID=5691ba02-e496-465a-bba9-b2f1182cdf24&displaylang=en
    \______________________________________________________________
    '@


        $encoder = new-object -com WMEncEng.WMEncoder
        $sc = $encoder.SourceGroupCollection
        $encoder.file.localfilename = $destination
        $profile = $encoder.profilecollection | ? { $_.name -eq $profile }

        # cycle through all WAV files and add a 'sourcegroup' for
        # each and assign correct encode profile.
        $sourcefiles = $sourcefiles | ? { $_.Extension -eq '.wav' }

        for ($i = 0; $i -lt ($sourcefiles.count); $i ++ ) {

            $sg = $sc.add($sourcefiles[$i].basename)
            $audsrc = $sg.addSource(1)
            $audsrc.setinput($sourcefiles[$i].fullname)
            $sg.profile = $profile

            # Set rollover to move to next Sourcegroup unless this is last file
            if ($i -lt ($sourcefiles.count - 1 )) { $sg.SetAutoRollover([int](-1),[string]$($sourcefiles[$i + 1].basename)) }
        }

        $sc.Active = $sc.Item(0)
        $encoder.autostop = $TRUE
        $encoder.PrepareToEncode($TRUE)
        $encoder.start()

        $totalwavesize = ($sourcefiles | Measure-Object length -Sum).sum

        do { $per = [int]((($destination | dir).length) / ($totalwavesize / 21) * 100)
            Write-Progress -Activity "Encoding Audio" -Status "progress" -PercentComplete $per
            start-sleep -milli 500
        } until ( $encoder.runstate -eq 5 )
        write-progress -Activity "Encoding Audio" -Status "progress" -completed

        $encoder.preparetoencode($FALSE)
        $encoder.SourceGroupCollection | % { $encoder.sourcegroupcollection.Remove($_.name) }
        $encoder.stop()
        $encoder = $null
    }

    function Rip-Audiobook {
        Write-Host @'
    ______________________________________________________________
    /  Rip-AudioBook:
    |   by Gaurhoth (http://www.skyeagle.net/blog)
    |  
    |  This script takes an Audio CD and rips each track to
    |  a set of WAVE files in a temporary folder. These WAVE
    |  files are then processed using Windows Media Encoder
    |  to a single merged WMA file that is saved in folder
    |  specified by $DestinationPath.
    |  
    |  Requirements:
    |    BonkEnc 1.07 |       http://www.bonkenc.org/
    |    Taglib-Sharp
    |       http://www.taglib-sharp.com/Download/
    |    Windows Media Encoder 9 (32bit tested)
    |       http://www.microsoft.com/downloads/details.aspx?FamilyID=5691ba02-e496-465a-bba9-b2f1182cdf24&displaylang=en
    \______________________________________________________________          
    '@


        $configfile="$PsScriptRoot\psbonkconfig.xml"
        $cddrive = 0 # change to reflect a different CD Rom drive.

        # Pull configuration information from xml file
        if (Test-Path $configfile) {
            $config = Import-Clixml $configfile
        } else {
            # No config file. Start from scratch.
            $config = "" | Select Title,Author,Series,cd,bonkexe,taglib,destinationpath
        }

        dir $PsScriptRoot -Filter "taglib-sharp.dll" -Recurse | % {
            $config.taglib = $_.fullname
            [void][Reflection.Assembly]::LoadFile($config.taglib)
        }

        Write-Host "Answer the following configuration questions (Pressing ENTER will use the default value shown)." -ForegroundColor Yellow

        # Try to find becmd.exe (bonkenc cmd line ripper) somewhere in the Module Root or subfolder.
        dir $PsScriptRoot -Filter "becmd.exe" -Recurse | % {
            $config.bonkexe = $_.fullname
        }
        while (-not ([io.file]::exists($($config.bonkexe)))) {
            Write-Host -foreground yellow "`nbecmd.exe path was not found. Please enter full path to becmd.exe."
            Read-Host "Enter path to becmd.exe ($($config.bonkexe))" | % { if ($_) { $config.bonkexe = $_ } }
        }

        if (-not $config.destinationpath) { $config.destinationpath = "$home\music" }
        Read-Host "Destination Folder `($($config.destinationpath)`)" | % { if ($_) { $config.destinationpath = $_ } }
        while (-not ([io.directory]::Exists($config.destinationpath))) {
            Write-Host "`nThe folder specified ($($config.destinationpath)) does not exists. Please specify a valid folder."
            Read-Host "Destination Folder `($($config.destinationpath)`)" | % { if ($_) { $config.destinationpath = $_ } }
        }

        # Ask for tag information using defaults from $config object
        # Pressing Enter accepts default value.
        Read-Host "Title `($($config.title)`)"   | % { if ($_) { $config.Title = $_ } }
        Read-Host "Author `($($config.Author)`)" | % { if ($_) { $config.Author = $_ } }
        Read-Host "Series `($($config.Series)`)" | % { if ($_) { $config.Series = $_ } }
        Read-Host "CD Number `($($config.CD)`)"  | % { if ($_) { $config.CD  = $_ } }

        $temp = New-Tempfolder

        $bonksession = Start-Process -elevated $config.bonkexe "-cd $cddrive -e WAVE -t 120 -d $temp -track all"
        write-host -foreground Yellow "`nPlease Wait... running BonkEnc to extract audio from your CD."
        $bonksession.waitforexit()

        (New-Object -ComObject WMPlayer.ocx).cdromCollection.Item($cddrive).eject()

        $destination = "{0}\{1} - {2}.wma" -f $config.destinationpath,$config.CD,$config.Title

        write-host -foreground Yellow "`nRunning Windows Media Encoder to convert the extracted audio to WMA..."
        if ( $temp | dir ) {
            Encode-Audio -destination $destination -sourcefiles $($temp | dir | sort)

            # Tag the WMA file
            $media = [TagLib.File]::Create($destination)
            $media.Tag.Artists = $config.author
            $media.tag.Album = $config.series
            $media.Tag.Title = $config.title
            $media.Tag.Track = $config.cd
            $media.Save()

            # Increment the track/cd number so it'll default to
            # correct number on next run.
            $config.cd = $([int]$config.cd + 1)
            $config | Export-Clixml $configfile

            Write-Host -Foreground Yellow "`n`nCompleted. CD has been saved to $destination."

        } else {
            write-host "Failed to find CD Tracks to encode. Be sure to insert a CD and close the Tray."
        }

        del "$temp\cd*track*.wav"
        del $temp -rec


    }

    Export-ModuleMember Rip-Audiobook

     

    Download Link: rip-audiobook.psm1 (6.98 kb)


    Categories: CTP | powershell | Modules
    Posted by gaurhoth on Tuesday, June 03, 2008 6:42 AM
    E-mail | Permalink | Comments (59) | Post RSSRSS comment feed

    Managing Podcasts with Powershell (Part 2)

    In my last part of this topic, I touched on using IE7's built in RSS Platform to setup a few podcasts to be automatically downloaded.

    I wanted to use Windows Media Player to sync the Podcasts with my MP3 player. My particular player (Sansa Fuze 8gb) requires the Genre tag to be set to 'Podcast' in order to show up in the approrpriate place in the UI.

    To start with, I create a NTFS symbolic link for each podcasts folder. Explaining Vista's implementation of symbolic links is beyond the scope of this article. See http://en.wikipedia.org/wiki/NTFS_symbolic_link if you want to begin a research project on them.

    All you really need to know is that by using symbolic links, I can access a folder using

    c:\users\gaurhoth\podcasts\{feed name}
    instead of
    C:\Users\gaurhoth\AppData\Local\Microsoft\Windows\Temporary Internet Files\Enclosure\{E4E0D525-2BAC-4618-BA87-3A6310945820}

    This does require Vista. Since we are using a LINK to the original folder that the RSS Platform manages, we can let the RSS Platform handle removing old enclosures instead of having to write extra code.

    The next big task that I let powershell handle for me is removing the Read Only attribute so that I can remove any Alternate Data Streams (another topic covered in many articles on the internet - search for 'Alternate Data Streams in NTFS'). This is equivalent to clicking 'UNBLOCK' in the Properties of certain files downloaded using IE.

    I also update the MP3 Genre Tag to say 'Podcast' using taglib-sharp which you can find at http://www.taglib-sharp.com/Download/.

    Setting up Windows Media Player is pretty straight-forward. Create an 'Auto-Playlist' to sync with your device like this: wmppod1

    Next, setup your library to pick up audio files from your podcasts folder (the symbolic link created using Powershell): wmplib1

     

    You can download the script here: podcastsync.ps1 and it's pasted below:

    # Require taglib-sharp. See http://www.taglib-sharp.com/Download/.
    # You'll find the compiled .NET 2.0 DLLs in taglib-sharp-x.x.x.x-windows.zip
    # Change path appropriately
    [void][Reflection.Assembly]::LoadFile("c:\Users\gaurhoth\ps\poshpodsync\taglib-sharp.dll")

    # Root of folder to store the symbolic links
    $podcasthome = "$home\podcasts"

    # Root of the Feed Folder where you are storing podcasts feeds
    $feedhome = 'Podcasts'

    if (-not [system.IO.Directory]::Exists("$podcasthome")) {
        Throw "$podcasthome does not exists."
    }

    # enumerate the feeds under under your $feedhome
    $feeds = (New-Object -ComObject Microsoft.FeedsManager).RootFolder.getsubfolder($feedhome)
    foreach ($feed in $feeds.feeds) {
        if (-not (Test-Path "$podcasthome\$($feed.Name)")) {
            #create NTFS Symbolic Links to path were IE7 stores the enclosures for each feed
            cmd /c "mklink /J `"$podcasthome\$($feed.name)`" `"$($feed.localenclosurepath)`""
        }

        get-childitem "$podcasthome\$($feed.name)" -Recurse -Include *.mp3,*.wma | % {
            Write-Host "$_"
            # Test for ReadOnly flag and remove if present
            if ($_.attributes -band [system.IO.FileAttributes]::ReadOnly) {
                $_.attributes = $_.attributes -bxor [system.IO.FileAttributes]::ReadOnly
            }

            # Simulates clicking 'UNBLOCK' on properties of a file downloaded
            # using Internet Explorer. Look up Alternate Data Streams in NTFS if your
            # curious.
            cmd /c "echo on > `"$($_):Zone.Identifier`""

            # Using taglib-sharp to make sure each podcast is tagged as a podcast.
            # My mp3 player uses the tag to create a separate list of files separate
            # from my music list.
            $media = [TagLib.File]::Create($_.fullname)
            $dirty = $FALSE
            if (-not $media.Tag.Artists) {
                $media.Tag.Artists = $feed.Name
                $dirty = $TRUE
            }
            if (-not $media.Tag.Album) {
                $media.Tag.Artists = $feed.name
                $dirty = $TRUE
            }
            if ($media.Tag.Genres -notmatch "Podcast") {
                $media.Tag.Genres = "Podcast"
                $dirty = $TRUE
            }
            if ($dirty) { $media.Save() }

            #replace Read-Only or IE RSS Platform doesn't clean up old enclosures.
            if (-not ($_.attributes -band [system.IO.FileAttributes]::ReadOnly)) {
                $_.attributes = $_.attributes -bxor [system.IO.FileAttributes]::ReadOnly
            }
        }
    }

     

    That's all for now.

    Gaurhoth


    Posted by gaurhoth on Sunday, April 13, 2008 11:25 AM
    E-mail | Permalink | Comments (124) | Post RSSRSS comment feed

    Managing Podcasts with Powershell (Part 1)

    I've never before embraced the idea of listening to podcasts on a regular basis. With the recent purchase of an MP3 Player, it's garnered more of my interest. Unfortunately, I haven't stumbled on an automated approach to manage getting the downloaded podcasts synced to my player. I'm a creature of great laziness and would quickly lose interest in podcasts unless I find a way dump new episodes to my player with as little effort as possible.

    I could probably find a client somewhere (iTunes? WinAmp?)... but what fun would that be?

    I decided to play with the built in RSS Platform that's included as a part of Internet Explorer 7 (as such, IE 7 must be installed on your system). The RSS Platform includes a COM object which we can utilize from Powershell with ease. You could also use the FEED provider from PSCX if you chose.

    Once you subscribe to the feed using IE7, view the Feed Properties and make sure you have the 'Automatically download attached files' option checked and set a reasonable limit for 'Keep the most recent items only'. I set my limit at 3 items. Keep in mind that if you totally automate this as I have, every podcast will be synchronized to your MP3 device which may have limited space.

    feed01

    Give the system some time to download your enclosures in the background.

    Now, we run into the downside of using IE7's RSS Platform. It stores the enclosures in an obscure folder under the Temporary Internet Files. Let's take a peek at the object that will let us dive into the RSS Platform and find these mysterious enclosure folders.

    $feeds = (New-Object -ComObject Microsoft.FeedsManager).RootFolder
    $feedpodcast = $feeds.GetSubfolder('Podcasts')

    I store all of my Podcasts in a folder off the root of the FEED listing called 'Podcasts'. The second line is getting the object that represents that level of feed listings.

    We can get a list of all feeds in this folder using this:

    66> $feedpodcast.feeds
    Type     Name                                             ItemCount UnreadItemCount
    ----     ----                                             --------- ---------------
    feed     Adventures of Superman Podcast                          47               0
    feed     Batman Adventures                                       25               0
    feed     British Science Fiction Podcast                          3               0
    feed     Hanselminutes                                            3               0
    feed     Mind Of Root                                             3               0
    feed     PowerScripting Podcast                                   3               0
    feed     PowerShell Basics                                        3               0
    feed     Science Fiction Theater Podcast                         58               0
    feed     Scifi Friday                                             3               0
    feed     X Minus One Podcast                                     46               0
    feed     .NET Rocks!                                              3               0
    67> 

    Now, let's find the enclosure path:

    84> $($feedpodcast.feeds)[5]  | fl Name,Url,LocalEnclosurePath,DownloadEnclosuresAut
    omatically
    
    
    Name                            : PowerScripting Podcast
    Url                             : http://feeds.feedburner.com/Powerscripting
    LocalEnclosurePath              : C:\Users\gaurhoth\AppData\Local\Microsoft\Window
                                      s\Temporary Internet Files\Enclosure\{1BA818DF-D3
                                      C1-447D-A57F-8097CD250521}
    DownloadEnclosuresAutomatically : True
    
    
    
    85> 

    Now we know where to find the downloaded podcast files. Whew. Armed with this, we'll be able to write a script that will tie in all of these Enclosure Paths into a single parent folder so that Windows Media Player can monitor and sync to my player. I'll save that for the next part.

    Gaurhoth


    Posted by gaurhoth on Saturday, March 29, 2008 7:47 PM
    E-mail | Permalink | Comments (20) | Post RSSRSS comment feed

    Get-NBTHosts

    * This is a repost from my original blog location *

    I've been a long time user of a very useful cmd line utility called NBTScan. NBTScan is similar to the Windows builtin cmd line utility NBTSTAT, but can operate on a range of IP addresses instead of a single IP. Using NBTscan, you can get a list of Windows machines that are configured to respond to NETBIOS and aren't behind a firewall. You can find some more information about NBTScan at http://www.unixwiz.net/tools/nbtscan.html, but that's an older version that doesn't support a couple of required parameters for this script. For the newest version that I've been able to find, look at http://inetcat.net/software/nbtscan.html.

    Here's a script I use to wrap the output into Powershell friendly custom objects.

    function Get-NBTHosts {

        param($iprange)

     

        if (!$iprange) {

          write-Host "You must specify an -iprange in CDIR notation.`r`n  Example: 192.168.1.0/24 "

          return

        }

     

       $iprange | % { nbtscan -t 500 -m 1 -s : $_  2>$null | % {

     

                $out = 1 |Select-Object IPAddress,Name,User,MACAddress

               

                $a = $_.split(":")

               

                $out.IPAddress = $a[0].trim()

                $out.Name = $a[1].replace("IS~","").trim()

                $out.User = $a[3].trim()

                $out.MACAddress = $a[4].trim()

               

                write-Output $out

            }

        }  

    }

    Example:

    PS D:\ps> Get-NBTHosts 10.150.5.0/24
    IPAddress                     Name                          User                          MACAddress
    ---------                     ----                          ----                          ----------
    10.150.5.3                    HHHSSC65SP5                   <unknown>                     XX-XX-XX-XX-XX-XX
    10.150.5.6                    HHHSQL                        <unknown>                     XX-XX-XX-XX-XX-XX
    10.150.5.8                    HHHFDBSVR                     <unknown>                     XX-XX-XX-XX-XX-XX
    PS D:\ps> 
    

    You'll need nbtscan and cygwin1.dll somewhere in your path so that Get-NBTHosts can find it or modify the script to point directly to location of nbtscan.


    Categories: powershell
    Posted by gaurhoth on Friday, October 05, 2007 3:48 AM
    E-mail | Permalink | Comments (34) | Post RSSRSS comment feed

    Using Powershell to Mail-Enable an AD User without CDOEXM

    * This is a repost from my original blog location *

    Over on microsoft.public.windows.powershell, it’s been asked how to mail-enable an AD user in an Exchange 2003 Environment. The MS supported way involves CDOEXM (part of Exchange System Manager) which seems to be rather difficult to use from powershell.

    In reality, you can usually get away with using [ADSI] to modify several key attributes on the AD user and let RUS initialize the remaining attributes to create the mail-enabled user.

    Here’s the example I posted on Usenet:

    $user = [ADSI]"LDAP://CN=Powershell Test,OU=Standard Users,OU=Site1,DC=testlab,DC=com"

    $user.mailNickname = "ptest"

    $user.msExchHomeServerName = "/o=testlab/ou=First Administrative Group/cn=Configuration/cn=Servers/cn=SITE1-03EX1"

    $user.setinfo()

    #wait for RUS - This can be seconds or hours depending on your Exchange configuration.

    # To see the changes, reassign the modified AD object to $user

    $user = [ADSI]"LDAP://CN=Powershell Test,OU=Standard Users,OU=Site1,DC=testlab,DC=com"

    $user | fl *

     

    The minimum attributes needed for RUS are mailNickname (Exchange Alias) and msExchHomeServerName.  You can see the format that msExchHomeServerName expects in the example and this will obviously be different for every exchange server. If you don’t fill in any additional attributes, the mailbox will be created in the default mail store on the server specified. If you need to point to a different mail store, you can use the homeMDB attribute.  Again, the easiest way to see the expected format is to grab an already mail-enabled user and take a look at the attributes:

     

     

    PS C:\> $user = [ADSI]"LDAP://CN=Powershell Test,OU=Standard Users,OU=Site1,DC=testlab,DC=com"                          
    PS C:\> $user | format-list cn,mailNickname,msExchHomeServerName,homeMDB,homeMTA,proxyAddresses                         
    cn                   : {Powershell Test}                                                                                
    mailNickname         : {ptest}                                                                                          
    msExchHomeServerName : {/o=testlab/ou=First Administrative Group/cn=Configuration/cn=Servers/cn=SITE1-03EX1}            
    homeMDB              : {CN=Mailbox Store (SITE1-03EX1),CN=First Storage Group,CN=InformationStore,CN=SITE1-03EX1,CN=Ser 
    vers,CN=First Administrative Group,CN=Administrative Groups,CN=testlab,CN=Microsoft Exchange,CN= 
    Services,CN=Configuration,DC=testlab,DC=com}                                                     
    homeMTA              : {CN=Microsoft MTA,CN=SITE1-03EX1,CN=Servers,CN=First Administrative Group,CN=Administrative Grou 
    ps,CN=testlab,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=testlab,DC=com}              
    proxyAddresses       : {SMTP:ptest@testlab.com, X400:c=US;a= ;p=testlab;o=Exchange;s=Test;g=Powershell;}                
    

     

    After you assign the necessary attributes and issue the .setInfo() method, you just have to wait for RUS to do it’s magic. This can take seconds or much longer. It just depends on how the Exchange environment is configured.

     

    As with anything that directly modifies AD attributes… TEST, TEST and TEST some more in a LAB. Never start in a production environment.

     

    gaurhoth


    Posted by gaurhoth on Wednesday, August 15, 2007 8:39 AM
    E-mail | Permalink | Comments (124) | Post RSSRSS comment feed