Search
Generic filters
Exact matches only
Filter by Custom Post Type

PowerShell Conference Europe 2017 Call For Speakers

Guys and Gals, do you want to have the opportunity to speak at one of the biggest PowerShell conferences in the world? Now you have it! Read my post here for the details and to sign up. Hurry up, because we will close the registration for speakers at the end of November. Also our site is now open for delegates to register. Check it out here: http://psconf.eu

How To Import User Pictures in Exchange Online

In a recent thread on the PowerShell.org forum, Jeremy Miller asked how to import user pictures in bulk in Exchange Online. I was providing some answers to Jeremy, and he asked me to explain the logic behind the solution (the one that worked for him actually). So I will try to explain it here.

The Script
$imageFolder = 'C:\Temp\Images\'
$pictures = Get-ChildItem $imageFolder


foreach ($picture in $pictures){
    
    Try {
        $user = Get-User -Identity $($picture.BaseName) -ErrorAction Stop
        }
    
    Catch {
        Write-Warning "Warning: $_"
    }




    If ($user) {
        $user | Set-UserPhoto -PictureData ([System.IO.File]::ReadAllBytes("$imageFolder\$($picture.Name)"))
    }
}

Annotations

  • Line 1: The path to the pictures is assigned to the variable $imageFolder
  • Line 2: The contents of the directory in the $imageFolder variable is assigned to the variable $pictures. This variable is of the type System.Array:
  • Lines 4-17: An foreach loop is being used here to iterate through each picture. This because on every picture an action will be performed.
  • Lines 6-12: I'm using a Try/Catch construction here, because I want to keep the foreach loop going; even when a user does not exists in Exchange Online. If a user exists, then the resulting user object is being assigned to the variable $user. If not, the the Try/Catch construct is throwing a error and continues with the next user.
  • Line 7: Here I'm searching for a user in Exchange Online. I feed the parameter Identity the BaseName of the $picture variable. BaseName is just the filename, without the extension. Jeremy was having picture files in his folder names like the SamAccountNames. So $($picture.BaseName) will give back the SamAccountName in Jeremy's situation. Get-User takes in the SamAccountName as value for the Identity parameter, and will therefore find (or not) find the user in Exchange Online.
  • Line 11: If a user cannot be found, the error message from the Get-User Cmdlet will be shown on in the shell. $_ means, 'current object in the pipeline'.
  • Line 14-16: If the $user variable contains something, we will execute Set-UserPhoto to assign a picture to the user. $user is being piped to Set-UserPhoto, so that I don't have to specify the -Identity parameter of the Set-UserPhoto Cmdlet. -Identity takes in values by property name. So where the piped object contains any value accepted by the parameter Identity, the Set-UserPhoto will execute the action on the user in Exchange Online.

Sample Usage

From the examples of Set-UserPhoto it can be seen that you can use the Set-UserPhoto as following:
Set-UserPhoto "Paul Cannon" -PictureData ([System.IO.File]::ReadAllBytes("C:\Users\Administrator\Desktop\PaulCannon.jpg"))
What I have done in the script is piping $user to Set-UserPhoto, so I don't have to use the parameter -Identity.
I also used a subexpression in the code: ("$imageFolder\$($picture.Name). PowerShell always executes this code first before executing the rest of the code. So this subexpression translates to 'C:\Temp\Images\PaulCannon.jpg'.
Conclusion
For all code I made use of Get-Help and Get-Member to put together the code. These are the single most important Cmdlets to know, to discover how to use the Cmdlet (in this case Set-UserPhoto.
To resumate:
  • Get-Help Set-UserPhoto -Full
  • Get-Help about_Try_Catch_Finally
  • Get-Help about_ForEach
  • Get-Help about_If

I hope this helps!

For your pleasure, The Old Nerdish Poem

I thought that my fellow Poshies could appreciate this. After seeing this funny post from Jaykul (Joel Bennet), I just made a quick 'n dirty piece of code, just for fun, to make your computer tell the poem.

Enjoy! (PS: the original is a lot better to listen to: The Nerdish Poem)

Add-Type -AssemblyName System.speech
$tts = New-Object System.Speech.Synthesis.SpeechSynthesizer

$poem = @('
waka waka bang splat, tick tick hash,
caret quote back tick, dollar dollar dash,
bang splat equal at, dollar under score,
percent splat, waka waka tilda number four,
ampersand bracket-bracket dot dot slash,
vertical bar curly-bracket; comma, comma, crash!
')

$tts.Speak($poem)

 

Quick Tip: Enable CredSSP trough GPO's

I thought I share a quick screenshot with you, how I implemented CredSSP trough a GPO in my testlab. This enables me to delegate my credentials to the computer I'm running my Cmdlet's on.

GPO-CredSSP

Improved Function: Get-ComputerDetail

Fellow coders, I received some great feedback from our honorary scripting guru's Mike F. Robbins and Richard Siddaway about my little function (thanks guys! I'll buy you a drink when we meet! 😉 ).

With their feedback I managed to improve my simple function. And that's so great about being part of a community; people are always willing to help.

#requires -Version 2
Function Get-ComputerDetail
{
    [cmdletbinding()]
    
    param (
    
        [ValidateNotNullOrEmpty()]
        [string[]]$ComputerName = $env:COMPUTERNAME
    
    )

    foreach ($node in $ComputerName)
    {
        
        try
        {
            $computerSystem		= Get-WmiObject -Class 'Win32_ComputerSystem' -ComputerName $node -ErrorAction Stop
            $computerBios		= Get-WmiObject -Class 'Win32_Bios' -ComputerName $node -ErrorAction Stop
            
            [pscustomobject][ordered]@{
                Name         	= $computerSystem.Name
                Manufacturer 	= $computerSystem.Manufacturer
                Model        	= $computerSystem.Model
                Serial       	= $computerBios.SerialNumber
            } # End of custom object
            
        } # End of try
        
        catch 
        {
            Write-Error -Message "The command failed for computer $node. Message: $_.Exception.Message"
            break
        }# End of Catch
    
    }# End of foreach

}# End of function

Update - What’s your favorite PowerShell Editor?

On june 9th, I've started a survey about the most popular PowerShell editor around: What's your favorite PowerShell Editor?

I have some results for you now, and it's quite clear.

Screen Shot 2015-06-15 at 19.32.48

Till now PowerShell ISE is the most popular editor. Well done Microsoft!

But please keep sending in your votes, let's make this the ultimate survey!

Vote here: Survey

Function: Get-ComputerDetails

Another nice addition for today. In the Powershell.org forums someone asked for retrieving computer information. This information is being retrieved from several WMI objects, and had to be combined in the results. For this PowerShell custom objects are the perfect fit.

The code:

#requires -Version 1
Function Get-ComputerDetails
{
    [cmdletbinding()]
    Param([string[]]$Computer)
    
    $result = @()

    foreach ($node in $Computer)
    {
        try
        {
            $customObject = [pscustomobject][ordered]@{
                Name         = (Get-WmiObject -Class Win32_ComputerSystem -ComputerName $node -ErrorAction Stop).Name
                Manufacturer = (Get-WmiObject -Class Win32_ComputerSystem -ComputerName $node -ErrorAction Stop).Manufacturer
                Model        = (Get-WmiObject -Class Win32_ComputerSystem -ComputerName $node -ErrorAction Stop).Model
                Serial       = (Get-WmiObject -Class Win32_Bios -ComputerName $node -ErrorAction Stop).SerialNumber
            }
        }
        catch 
        {
            Write-Error -Message "The command failed for computer $node. Message: $_.Exception.Message"
            break
        }
        $result += $customObject
    }
    $result
}

To use it:

Get-ComputerDetails -Computer or01,dc01,ipam01

Function: Expand-ZipFile

Fellow coders, I've got a quick and dirty function for you. I had the requirement to extract zip files from a particular directory. Of course you could do this with Expand-Archive (new in PowerShell 5).

But there's a problem with this little rascal; it does not keeps the timestamps of the zipped files intact. My customer wanted to keep these timestamps intact, because they use it as a indicator to see if the file is older or newer what they already have.

So I made a quick and dirty function, which uses a .NET assembly. I based this function on code I remembered from somebody else, but I cannot remember or find that source anymore.

This function takes in a sourcepath, which contains your zip files. The destinationpath is the place where you want to place the extracted files. The overwrite switch determines if existing files in the destinationpath has to be overwritten or not.

#requires -Version 2
function Expand-ZipFile()
{
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory = $true,Position = 0)][string]$SourcePath,
        [Parameter(Mandatory = $true,Position = 1)][string]$DestinationPath,
        [Parameter(Mandatory = $true,Position = 2)][bool]$Overwrite
    )

    Add-Type -AssemblyName System.IO.Compression.FileSystem

    try
    {
        foreach($sourcefile in (Get-ChildItem -Path $SourcePath -Filter '*.ZIP')) 
        {
            $entries = [IO.Compression.ZipFile]::OpenRead($sourcefile.FullName).Entries
        
            $entries | ForEach-Object -Process {
                [IO.Compression.ZipFileExtensions]::ExtractToFile($_,"$DestinationPath\$_",$Overwrite)
            }
        }
    }
        
    catch
    {
        Write-Warning -Message $_.Exception.Message
    }
}

What's your favorite PowerShell Editor?

Just for my interest, a short survey. What is your favorite PowerShell Editor?

Read more

PowerShell <3 SSH

Richard’s Log, Stardate 2457176.5

Our destination for today is the love story between PowerShell and SSH.

Yesterday Microsoft announced that they will integrate SSH into PowerShell. The PowerShell team at Microsoft already tried 2 times before, to get SSH into PowerShell. Now, under the wings of new management, and I think Satya Nadella has a big influence in this, they finally have a go.

With SSH you can have secure, encrypted (based on strong algorithms) connections to your Windows Servers, using public/private RSA key authentication. This means that you natively can manage Linux from Windows, and vice versa, without installing any additional tools.

The full story can be read here: Looking Forward Microsoft Support SSH

A bit of time ago there was a discussion on the PowerShell.org forum, about having PSRemoting enabled by default. There were people for and against it. I'm not sure what I would like; to have something enabled by default so I can manage it immediately, or having it disabled and thus more pre-work to start managing my systems (but have it more secure).

Now that Microsoft will add support for SSH, I suspect that maybe PSRemoting still will be enabled by default (they have to, otherwise you can't configure the system), but that SSH will be your first entry point to the system, instead of the HTTP listener.

Adding SSH support in PowerShell is a great idea, and I hope Microsoft will implement it in a way that makes Server more secure.

Skip to toolbar