Exploring iTunes Using PowerShell Part 3: Connected Devices

Continuing on with my article on PoweShell and iTunes, I am now going to show you how to find out what devices are currently connected to iTunes. By connected, I mean that the device is actually showing up as being connected to iTunes to be able to sync, update or ejecting the device from iTunes.

First thing is first: connect to the iTunes COM object.

 
$itunes = New-Object  -ComObject iTunes.Application

Now that we have accomplished that, I also need to connect my iPhone to my computer so it actually shows up in iTunes. Once that has been done, we can start digging for information on the iPhone.

The “source” of what we are looking for just happens to reside in a property call…wait for it…sources.

 
$Sources = @($itunes.Sources)
$Sources

image

Note: I have to cast the results as an array using @() when dealing with COM objects, otherwise it will be treated as a single item in the collection.

In this case, the iPhone is easily distinguished by its name. But what if the device had another name or there were more sources than just these 3? We need to look at the kind property as the means to filter our the sources. Fortunately, looking through the SDK allowed me to find the enum to map the integer to what kind of source I am dealing with.

enum
ITSourceKind {
ITSourceKindUnknown = 0,
ITSourceKindLibrary,
ITSourceKindIPod,
ITSourceKindAudioCD,
ITSourceKindMP3CD,
ITSourceKindDevice,
ITSourceKindRadioTuner,
ITSourceKindSharedLibrary
}

This can easily be made into a hash table.

 
$SourceKind = @{
    Unknown = 0
    Library = 1
    iPhone = 2
    CD = 3
    MP3 = 4
    Device = 5
    Radio = 6
    SharedLibrary = 7
}

Now I can filter out the sources to find my actualy iDevice.

 
#Need Kind -eq 2
$iPhone = $Sources | Where {
    $_.Kind -eq $SourceKind.iPhone
}

#View the actual iPhone device
$iPhone

image

Here I can see the size of the of device as well as how much free space is left. I can also locate the version of the iOS (8.1 in this case). So this is pretty neat, but I wonder what methods are available for me to use?

 
$iPhone | Get-Member -MemberType Method

image

Each of these does what you would expect them to:

  • EjectIpod ejects the iDevice from the computer
  • UpdateIpod attempts to update the software on the iDevice, assuming that is what you want to happen.

In this case, I won’t be demoing these two methods as they are pretty straightforward and require no additional parameters to the methods.

I can take a look at my playlists and see what I have.

 
@($iPhone.Playlists) | 
Select Name, Time, @{L='SizeGB';E={"{0:N}" -f ($_.Size/1GB)}} | 
Format-Table –AutoSize

image

I’m curious as to what I have for Podcasts on my iPhone currently. I know that under playlists, it is the third index in the collection.

 
@($iPhone.Playlists)[3]

image

Now let’s see what all is in here.

 
@(@($iPhone.Playlists)[3].Tracks) | 
Select-Object Name, Album, Artist, DateAdded, 
@{L='SizeGB';E={"{0:N}" -f ($_.Size/1GB)}}, Genre, Description, Time

image

Pretty cool! I won’t dive much more into playlists as I am going to spend more time with that at a later date. But here you can see what I have on my iPhone currently.

Unfortunately, there really isn’t a lot I can uncover using the COM object about my device, at least not publicly (the SDK doesn’t even mention anything else). But if I happen to find anything else out, I will be sure to write about it!

Posted in powershell | Tagged , , , | Leave a comment

Exploring iTunes Using PowerShell Part 2: The Equalizer

Using PowerShell, we have already seen what we can access with the iTunes COM object. The following article was already published:

Now I am going to step further along with this and show off the equalizer in this application and how you can manipulate it.

First off, we connect to the COM object, which will also open up the iTunes application.

 
$itunes = New-Object  -ComObject iTunes.Application

Let’s take a look at the equalizer and see if it is enabled.

 
$itunes.EQEnabled

image

Looks like it isn’t enabled, so with that we will enable it.

 
$itunes.EQEnabled = $True

If you want to view all of the equalizer presets we can use the EAPresets property to view them all. In this case, I am going to pipe them into a gridview using Out-GridView.

 
$itunes.EQPresets | Out-GridView

image

An audio person would know more about this stuff than me, but I can see each preset and the various properties that is has in regards to the different Bands.

Each of these Bands is modifiable (+12 or –12 are the limits) and you can even rename or delete these as well using the appropriate methods!

image

What about creating an EQ Preset? Well, don’t worry about that because it is possible to do as well! We can use the CreateEQPreset method from the main iTunes COM object to accomplish this. All we need is a name for it to supply as a parameter.

 
$NewEQPreset = $itunes.CreateEQPreset('TestPreset')

image

Here we have a new preset that is ready to be configured for use. Simple enough, right? I’ll make some changes to it so it seems more official.

 
1..10 | ForEach {
    $NewEQPreset."Band$($_)" = Get-Random (-12..12)
}
$NewEQPreset

image

Now we can set this equalizer as the current EQ Preset by replacing the CurrentEQPreset.

 
$itunes.CurrentEQPreset = $NewEQPreset

image

The last thing to cover is the Equalizer window that is in iTunes. This is a UI and really serves no purpose as far as command line stuff goes. But I wanted to include this so you can play around with it as well!

To look at the equalizer window, we have to view the EQWindow property of the iTunes object.

 
$itunes.EQWindow

image

All of the highlighted properties are editable and will instantly affect the UI when modified.

image

I can minimize or restore the UI window.

 
#Minimize
$itunes.EQWindow.Minimized=$True

#Restore
$itunes.EQWindow.Minimized=$False

Trying to modife the Zoomed property ends in failure though.

Exception setting “Zoomed”: “The specified operation is not currently
supported by the window.”
At line:1 char:1
+ $itunes.EQWindow.Zoomed = $true
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotSpecified: (:) [], SetValueInvocationExceptio
n
+ FullyQualifiedErrorId : CatchFromBaseAdapterSetValueTI

We can easily reposition the window using the top,and left properties (bottom and right are not supported).

 
$itunes.EQWindow.Top = 250
$itunes.EQWindow.Left = 800

Setting the Width and Height also appears to be unsupported by the window as well as it will throw errors when attempting to set a value on the property.

With that, we have covered the equalizer in iTunes. I’ll continue my exploration of iTunes with PowerShell with another article at some point in the future!

Posted in powershell | Tagged , , , | Leave a comment

New Column at MCPMag.Com!

My first column is already out, but I wanted to post that I have taken on a writing gig with MCPMag.com. This was an offer that I really couldn’t pass up as it gives me an opportunity to reach out to more folks about PowerShell and provide useful information to them as well. I am excited to be writing for MCPMag.com and look forward to sharing my knowledge with more people.

So what does that mean for my other blogging and projects that I do? Nothing! I am still going to continue writing on my personal blog and trying to keep with the trend of 4 posts a month (minimum) and am still going to be contributing for Hey, Scripting Guy!. In fact I have a 5 day series starting up at the beginning of December on script troubleshooting that I am excited to show off! This is just another opportunity to talk about something that love to work with and share my knowledge (as well as learning from the rest of the community in the comments) with everyone else!

With that, I found that my first column went live during the MVP Summit (which is awesome by the way!) and it is talking about viewing certificates using PowerShell on remote systems either using Remoting or through .Net if remoting is not applicable in your environment. Check it out and let me know what you think!

http://mcpmag.com/articles/2014/11/04/expiring-certs-in-powershell.aspx

Posted in News, powershell | Tagged , , , , | Leave a comment

Looking More at System.Array With PowerShell

I had written about why you shouldn’t use System.Array and instead should use System.Collections.ArrayList and went over the performance gains regarding this. I had mentioned that each time you add something to the System.Array, that it rebuilt itself while adding the new value. You pretty much took my word on that (thank you!) but I wanted to take that a step further by showing you how this can be viewed using PowerShell along with another quirk with using System.Array that you may not actually be aware of.

So how do we view this happening you ask? Glad you asked that question! We can make use of PowerShell’s own debugging using Set-PSDebug and setting the Trace level to 2 which will allow us to view all of the variable assignments.

 
Set-PSDebug –Trace 2

Now that we have done this, anything that occurs on the console will have some Debug output stream showing up on the screen as well. So now that this is done, lets create the array and start adding stuff to it.

 
$Array = @()
1..10 | ForEach {
    $Array += $_
}

SNAGHTML79fd1e6b

Each time a new item is added to the array, it builds a new array to add the new item into the collection.

The next part of this is something that I wasn’t aware of until I just happened to run the Clear() method while keeping the debug running and then adding some more data to it.

 
$Array.Count
$Array.Clear()
1..2 | ForEach {
    $Array += $_
}

SNAGHTML7a00fb4f

Instead of adding the new items at the front of the collection, they are instead being added at the end, like the values were never actually cleared at all! And guess, what? They were cleared, but just never removed from the collection.

 
$Array.count

image

While you would think that it should only be 2 items, it in fact is 12 items in the collection. The difference is that the first 10 items are actually Null.

 
For ($i=0;$i -lt $Array.count;$i++) {
    "Iteration: $i"
    $Array[$i]
}

$Array | ForEach {
    $_ -eq $Null
}

image

While this was new to me, it is actually by design (it pays to read up on the methods that you use Winking smile). What is happening is that each item in the collection is set to a specific type of value, in this case Null. More on the Clear() method can be found here.

So with that I hope you have a better understanding of using Set-PSDebug to look a little deeper into using System.Array and what happens when you use the += operator to add items to it as well as looking at what Clear() actually does.

Posted in powershell | Tagged , , , | 2 Comments

Using a ScriptBlock Parameter With a PowerShell Function

You may have noticed in some cmdlets that you can apply a scriptblock to certain parameters and have the scriptblock run during the code execution of the cmdlet. Take Sort-Object for example. I can use a scriptblock to perform a sort by the length of the filenames.

Why Use a ScriptBlock?

So why do this? Well, if a cmdlet supports pipeline input, you don’t want to pipe that information into  ForEach {} and have to iterate through each item because that defeats the purpose of just being able to chain commands together. What looks better?

This:

 
Get-ChildItem | Invoke-SomeAction -Action {$($_.name).OLD}

Or This:

 
Get-ChildItem | ForEach {
    Invoke-SomeAction -Action "$($_.Name).OLD
}

Personally, I am more of a fan of utilizing the pipeline to its maximum capability if allowed to do so.

Let’s take a look at a couple of examples that use parameters which support a scriptblock.

 
Get-ChildItem -File | 
Sort-Object {$_.Name.length} -Descending | 
Select Name

image

Rename-Item is another cmdlet that has similar capabilities.

 
Get-ChildItem -Filter *.Zip | 
Rename-Item -NewName  {$_.Name -replace 'zip','OLD'} –WhatIf

image

Here I found any .ZIP file and renamed it to .OLD instead.

So the next question is “How can I do something like this with my own functions?”. Glad you asked that! It really isn’t too difficult to setup a parameter which supports scriptblock use in your script or function.

Edit: Fellow PowerShell MVP Dave Wyatt pointed out in the comments that the scriptblock evaluation happens on its own through an undocumented feature in PowerShell that will invoke the scriptblock, thus erasing the need for any of the code samples that I use below. I am keeping this though for historical reasons and because this continues to show why I blog because if I am wrong, I promise that the correct information will show up at some point by someone who has more knowledge of the subject.

Basically the parameter binder will invoke the scriptblock as long as the parameter supports pipeline input. A quick look at this can be done using Dave’s function as an example and then running a Trace-Command against ParameterBinding.

 
Function Test-ScriptBlockParam {
    Param (
    [parameter(Mandatory, ValueFromPipelineByPropertyName)]
    [string] $Name
    )

    Process {
        $Name
    }  
}

Trace-Command ParameterBinding -PSHost {
    Get-ChildItem | Test-ScriptBlockParam -Name {$_.fullName -replace '(.*)\..*','$1'}
}

scriptblockbinder

Here you can see where the scriptblock is being invoked and the results of it are shown a couple lines later. Much easier to let PowerShell do all of the heavy lifting than to code it youself :).

Build Your Own Parameter

My function that I am going to build out will be called Test-ScriptBlockParam and I will allow a couple of parameters: InputObject and Name. I need one of these parameters to have pipeline support and the other can function without pipeline support (but will be my scriptblock parameter).

 
Function Test-ScriptBlockParam {
    Param (
        [parameter(Mandatory,ValueFromPipeline)]
        [Object[]]$InputObject,
        [parameter(Mandatory)]
        [Object]$Name
    )

So far so good. I am going to define how Name will be used as a scriptblock in the beginning of the function (or Begin{] block since I am using pipeline parameters).

 
Begin {
    If ($PSBoundParameters['Name']) {
        If ($Name -isnot [scriptblock]) {
            $Name = [scriptblock]::Create("Write-Output $Name")
        } Else {
            $Name = [scriptblock]::Create( ($Name -replace '\$_','$Object'))
        }
    }   
}

I want this to work regardless of whether a scriptblock was assigned as the parameter type or not. If a string is used, then it will build out a scriptblock using [scriptblock]::Create() and if a scriptblock has been applied, it makes an adjustment so it works properly in the Process block by replacing the $Name with $Object. This will make more sense after you see the Process{} block.

 
    Process {
        ForEach ($Object in $InputObject) {
            $Name.InvokeReturnAsIs()
        }
    }  
}

Here is the Process block where you see why I had to replace $Name with $Object. Because $Object is the variable that represents an item in the $InputObject collection, it can now run the scriptblock using InvokeReturnAsIs(). This means that whatever I have defined in the scriptblock will run and return the output.

Let’s give this a run and see what happens!

 
Get-ChildItem | 
Test-ScriptBlockParam -Name {"Name of File is: $($_.Name)"}

image

 
Get-ChildItem | 
Test-ScriptBlockParam -Name {$_.Name -replace '(.*)\..*','$1'}

image

 
Get-ChildItem | 
Test-ScriptBlockParam -Name {
    If ($_.PSIsContainer) {
        Write-host $_ -ForegroundColor Green
    } Else {
        Write-Host $_ -ForegroundColor Yellow
    }
}

image

So there you go! We have created a function that allows the use of a scriptblock parameter to perform an action that still allows us to use the pipeline more efficiently rather than working with ForEach.

In Closing

Of course, these are very simple examples of what you can do, but I would love to see what you have done using this a scriptblock parameter. So feel free to drop me a comment letting me know what you have done.

Posted in powershell | Tagged , , | 7 Comments