Mario's Blog

Get-Info -Subject IIS, PowerShell, SQL, Windows

Create a Virtual Exchange 2010 Datacenter

Technet Magazine published an interesting article about best practices for creating a virtual Exchange 201 Datacenter.

You find the article here: http://technet.microsoft.com/en-us/magazine/hh641416.aspx

Windows Management Framework 3.0 Community Technology Preview (CTP) #2 Available for Download

The PowerShell team released CTP2 of the Windows Management Framework 3.0. It contains PowerShell 3.0, WMI and WinRM.

It is available voor download at http://blogs.msdn.com/b/powershell/archive/2011/12/02/windows-management-framework-3-0-community-technology-preview-ctp-2-available-for-download.aspx.

Update: Get stream statistics from Wowza Media Server

Yesterday I discovered that the function in the article ‘Get stream statistics from Wowza Media Server’ was not working properly. It goes wrong when more Applications are loaded in Wowza. So I have changed the function and used ForEach loops instead of For loops. The For loop would also go wrong when there is only one stream in an Application. Because there is no count property in the XML object then.

Function Get-WowzaStreamStats{
    $webclient = new-Object System.Net.WebClient
    $webclient.credentials = new-Object system.Net.NetworkCredential("user", "password", "")
    [xml]$xml = $webclient.DownloadString("http://wowza-ip:8086/connectioncounts")

    foreach ($vhost in $xml.WowzaMediaServer.VHost) {

        foreach ($Application in $xml.WowzaMediaServer.VHost.Application) {

            foreach ($Stream in $Application.ApplicationInstance.Stream) {
                $Node = @{}

                $Node.TotalConnections = $Stream.SessionsTotal
                $Node.StreamName = $Stream.Name
                $Node.FlashConnections = $Stream.SessionsFlash
                $Node.SilverlightConnections = $Stream.SessionsSmooth
                $Node.RTSPConnections = $Stream.SessionsRTSP
                $Node.iOSConnections = $Stream.SessionsCupertino
                $Node.Application = $Application.name
                $Node.Vhost = $vhost.name

                $StreamStats = new-Object PSObject -Property $Node
                Write-Output $StreamStats
            }
        }
    }
}

Get stream statistics from Wowza Media Server

Recently I needed to know how many connections were made to a stream on our Wowza server, as real time as possible. For Windows Media Services you can use performance counters for that. And you can read these counters with PowerShell. I made a script for that in the past.

For Wowza I wanted something similar for that. The good thing is that Wowza has an xml interface that outputs the current connections. In default configuration you find the interface at http://wowza-ip:8086/connectioncounts. For humans the output is not very readable. So I made a function to parse the output.

Function Get-WowzaStreamStats{
    $webclient = new-Object System.Net.WebClient
    $webclient.credentials = new-Object system.Net.NetworkCredential("user", "password", "")
    [xml]$xml = $webclient.DownloadString("http://wowza-ip:8086/connectioncounts")

    for ($i=0; $i -lt $xml.WowzaMediaServer.VHost.Application.ApplicationInstance.Stream.Count; $i++) {
    $Node = @{}

    $Node.TotalConnections = $xml.WowzaMediaServer.VHost.Application.ApplicationInstance.Stream[$i].SessionsTotal
    $Node.StreamName = $xml.WowzaMediaServer.VHost.Application.ApplicationInstance.Stream[$i].Name
    $Node.FlashConnections = $xml.WowzaMediaServer.VHost.Application.ApplicationInstance.Stream[$i].SessionsFlash
    $Node.SilverlightConnections = $xml.WowzaMediaServer.VHost.Application.ApplicationInstance.Stream[$i].SessionsSmooth
    $Node.RTSPConnections = $xml.WowzaMediaServer.VHost.Application.ApplicationInstance.Stream[$i].SessionsRTSP
    $Node.iPadConnections = $xml.WowzaMediaServer.VHost.Application.ApplicationInstance.Stream[$i].SessionsCupertino

    $StreamStats = new-Object PSObject -Property $Node
    Write-Output $StreamStats
    }
}

The output of the function is an object. So you can use it in the pipeline. For example you can type:
Get-WowzaStreamStats | Where-Object {$_.StreamName –eq ‘name.stream’}

Add hundreds of hostheaders to one website with PowerShell

At the moment I am busy with replacing an old server with a new server running Windows Server 2008 R2. This old server has a few websites. Migrating a website is normally not difficult to do. Have done these migrations many times already. But one of the websites has hundreds of hostheaders attached to it. So this is not something you want to do by hand.

The good thing was that I had all these hostheaders already in a textfile. With the help of PowerShell it was easy to add these hostheaders to the website on the new server. I used this one-liner.

Get-Content c:\urls.txt | Foreach-Object {New-webbinding -name “Default Website” -IPAddress “*” -Port 80 -HostHeader $_}

Before you do this make sure you have added the WebAdministration module to your PowerShell console with Import-Module -Name WebAdministration.

Upload a file with ftp using PowerShell

Recently I needed a script to upload log files from one server to another server. The servers were in separate networks so I could not use a simple copy command like xcopy or robocopy. For this I had to use FTP. I had already a simple old batch file that uses the built-in ftp command. But I wanted to use PowerShell so that I could make it more advanced. After some searching on PowerShell websites I found some examples. I used these as a start for my function.

function Send-FileToFtp {
    [CmdletBinding()]
    [OutputType([System.Int32])]
    param(
        [Parameter(Position=0, Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [System.Object]$SourceFile,

        [Parameter(Position=1, Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [System.String]$Destination,

        [Parameter(Position=2, Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [System.String]$UserName,

        [Parameter(Position=3, Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [System.String]$Password
    )

    Process {
        try {
            # Get the object used to communicate with the server. 
            $Request = [System.Net.FtpWebRequest]::Create("ftp://$Destination/$($SourceFile.Name)")
            $Request.Method = $Request.Method = [System.Net.WebRequestMethods+ftp]::UploadFile 

            # This example assumes the FTP site uses anonymous logon. 
            $Request.Credentials = New-Object System.Net.NetworkCredential $UserName,$Password 

            # Copy the contents of the file to the request stream. 
            $FileContents = [System.IO.File]::ReadAllBytes($SourceFile.FullName)
            $Request.ContentLength = $fileContents.Length
            $RequestStream = $request.GetRequestStream()
            $RequestStream.Write($FileContents, 0, $FileContents.Length)
            $RequestStream.Close()
            $Response = $Request.GetResponse()
            $Response.StatusDescription
        }
        catch {
            throw "ERROR: Unable to upload file $($SourceFile.name), status {0}"
        }
        $Response.StatusDescription
        }
    }

The function takes 4 parameters as you can see in the script. Most of them will be self explaining. But the parameter $SourceFile will need some explanation. Instead of using a string I decided to use an object. I did this so I can use the object to construct the filename of the source and also use it to construct the ftp request. To use the function you can write something like this.

$files = Get-ChildItem -Path "c:\windows\system32\logfiles\" -Filter "*.log"
if ($files -ne $null) {
    Foreach ($file in $files) {
        $result = Send-FileToFtp -SourceFile $file -Destination "ftp.domain.com/folder" -UserName "user" -Password "password"
        if ($Result -match "226*"){
            "Upload completed, now deleting source file: $($File.Name)"
        } else {
            "Upload failed!"
        }
    }
}

It gets all the log files from the c:\windows\system32logfiles directory and places them in the variable $files. For every file object in the variable $files it runs the function Send-FileToFtp. If the upload succeeds, the function returns a StatusDescription with the code 226, you can delete the original file or do something else. When the upload fails you can output a message or do somethings else.

For what I wanted to do this works perfect. But for other things it possibly needs to get changed a bit.

Free Microsoft iSCSI Software Target

Today I saw a Twitter message about an iSCSI Software Target from Microsoft. With this you can turn any Windows Server 2008 R2 in an iSCSI device. The software target is the same that is being used in the Windows Storage Server product. So you can say that it is a proven technology.

At the office we will not make much use of it i think because we have Equallogic iSCSI devices in our datacenters. But I am going to use it for my test environment at home. This makes it easier for me to try and test iSCSI related stuff.

And maybe there will be a use for this in the office.

 

How to change the primary group of an AD user?

In the past I have made a PowerShell script that did some cleanup in the Active Directory on accounts of former employees. Like disable their account, move to a different OU and archive home and profile directory. In that script I use the Quest AD Cmdlets for all the AD actions. Although I like these cmdlets, I wanted to modify the script so that it uses the built-in AD cmdlets that are built in Windows Server 2008 R2.

Replacing the Quest AD Cmdlets with the built in cmdlets was not very difficult. But I had one little problem. We prefer to remove old accounts from all the groups they belong to. This way you will not find disabled or not existing accounts in the groups. But one group is assigned as the Primary Group and you cannot remove a user from this group. Default this is the ‘Domain Users’ group.

In the old script we added the user account to a special group called ‘Former Employees’, make this the Primary Group and remove all the other groups including ‘Domain Users’. With the Quest AD Cmdlets is fairly easy to do with the cmdlet Set-QADuser. Unfortunately this was not possible with the cmdlet Set-ADuser.

I tried to find a solution with Google but was not very successful. All the answers I found refer to ADSI or the Quest AD Cmdlets. So I have made my own function for this using the built-in AD Cmdlets from Windows Server 2008 R2. The user has to be a member of the group before you can make it the Primary Group!

Function Set-PrimaryGroup {
    Param (
        [string]$username=$(Throw "Error: Please enter a username!"),
        [string]$groupname="Domain Users")

Process {
    Try {
        #Get the DistinguishedName of the user for you want to change the primary group
        $UserDistinguishedName = (get-aduser -Identity $username -ErrorAction Stop).DistinguishedName
        Try {
            #Get SID of the Group that will become the primary group
            $GroupSid = (Get-ADGroup -Identity $groupname -Properties PrimaryGroupID -ErrorAction Stop).SID

            #Get the last 4 digits of the SID to become te PrimaryGroupID
            $PrimaryGroupID = $GroupSid.Value.Substring($groupsid.Value.LastIndexOf('-')+1)

            #Replace the PrimaryGroupID of the user with its new value. The user has to be already a member of this group.
            Set-ADObject -Identity "$UserDistinguishedName" -replace @{PrimaryGroupID=$PrimaryGroupID}
            Write-Host "$groupname set as primary group for user $username"
        } Catch {
            Write-Host "Error: Unable to find the PrimaryGroupID for group $GroupName! Maybe the group does not exist." -ForegroundColor red
        }
    } Catch {
        Write-Host "Error: Unable to find user $username!" -ForegroundColor red
    }
  }
}

Introduction to PowerShell Modules

A new feature in PowerShell 2.0 are modules. A module is a collection of PowerShell cmdlets and are an easier way to distribute cmdlets. For PowerShell snapins were used for this. But you needed developer skills to create snapins. But most system adminstrators are not developers.

Jonathan Medd wrote an interesting article about how to create your own modules, yu can find it on http://www.simple-talk.com/sysadmin/powershell/an-introduction-to-powershell-modules/. After reading this article it sounded much simpler to do then I thought.

Get-Weather script

Today I was searching the poshcode.org website for an ftp script. But my eyes caught another interesting script, wel actually it is a PowerShell function and it is called Get-Weather. It does exactly what you would expect. It tells you about the current weather in the city you specify. I thought it was a nice script for me as I will go soon to Brazil. And I think it is also a good example how to use webservices with PowerShell.

For example Get-Weather -Country “Brazil” – City “São Paulo”.

For more information about the function and to get the code. Follow this link http://boeprox.wordpress.com/2011/02/15/retrieving-weather-information-from-a-web-service-provider/.

Follow

Get every new post delivered to your Inbox.