Friday, August 30, 2013

Zip files and folders with PowerShell

One of the more frustrating things in this day of PowerShell v3 is not having cmdlets that can simply manipulate ZIP archives.

It is right there in the Windows GUI, but is it easy to automate?  Nope.

In fact if you search around you will find lots of different ways to handle this, one getting more complex than the next.  You will also find community projects that attempt to do the same thing.

One common reference that I ran across was this:

http://blogs.msdn.com/b/daiken/archive/2007/02/12/compress-files-with-windows-powershell-then-package-a-windows-vista-sidebar-gadget.aspx

From the spectacular David Aiken. I have to admit, it is not the first time he has saved my bacon.

His solution is built in, no funky community add-ins, nothing strange I can’t follow, and best of all it is compact – it is really small.

I have already had to do some things with Shell.Application with PowerShell, so I figured I would give it a shot.

Well, I immediately ran into some issues. 

One, his use of –Recurse.  Not necessary.  Use Get-ChildItem and pipe in the folder and then entire folder is zipped.  Perfect.  So you can work the input just about any way you like and it will simply pass whatever you pipe to it.

Two, file locking.  This tripped my up for hours.  And lots of other folks that have found his solution too.  His little 500 millisecond wait before advancing on to the next is simply not real nor flexible based on varying file sizes.

I found all kinds of folks commenting on the same thing and developing all kinds of fancy solutions to handle it.  But, in the end I found something really simple, and it was buried right there in the shell.application all along.  Simply test for the existence of the item you are zipping in the zip archive.

So simple.  One little do loop.  With my crafty Until ( $zipPackage.Items() | select {$_.Name -eq $file.Name} )

And, I only modified the Add-Zip, since David already had a fail safe to create the .ZIP if it didn’t already exist.

I am going to update my use of his usage example as well.

In my case I have a number of XML files.  Each is in a unique Folder.  There are other files and folders with the XML files as well (this is an OVF, for you OVF fans).

I want to create the .ZIP one level up from the folder where the XML is.

$ovfFolder = Get-Item $xmlFile.PSParentPath 

$zipFullName = $ovfFolder.Parent.FullName + "\" + $xmlFile.BaseName + ".zip"

Get-ChildItem $ovfFolder | Add-Zip $zipFullName

Now, below is my modification to the original Add-Zip function.

function Add-Zip  # usage: Get-ChildItem $folder | Add-Zip $zipFullName
{
    param([string]$zipfilename)

    if(!(test-path($zipfilename)))
    {
        set-content $zipfilename ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
        (dir $zipfilename).IsReadOnly = $false   
    }
    $shellApplication = new-object -com shell.application
    $zipPackage = $shellApplication.NameSpace($zipfilename)
    foreach($file in $input)
    {
        $zipPackage.CopyHere($file.FullName)
        do {
            Start-sleep 2
        } until ( $zipPackage.Items() | select {$_.Name -eq $file.Name} )
    }
}

Wednesday, August 28, 2013

PowerShell to test if a network connection is up and on the domain

If you have noticed I have been spending a lot of time working with deployments, deploying, and scripting configurations.
In fact, I have spent nearly two years, off and on, working on this in various ways and permutations from Windows Azure VMRole (the now dead non-persistent one) to SCVMM Service Templates.
The thing that makes this type of scripting unique is that the scripts are executed within the OS of the VM, not externally from some manager that uses a PowerShell remoting session or the like.
This means that each script has no knowledge of anything beyond the boundaries of the OS where the script is running.
Now, I assume that many of you are aware of the Hyper-V Synthetic Nic, and that the Synthetic NIC driver comes to life later in the boot process (not in 2012 R2 generation 2 VMs, but that is different).
The problem is one of timing.  Your script could be running prior to your network being awake an functional.
Here is a little script that I use to test my domain joined machines prior to continuing when I have a need for domain connectivity (such as executing a command using a domain credential).

Do { $upTest = ( Get-NetConnectionProfile | where {$_.IPv4Connectivity -ne "NoTraffic"} ) } until( $upTest.NetworkCategory -eq "DomainAuthenticated" )
If you want to take this to the next level and identify the IP address and physical NIC (say you have multiple NICs and you need to bind to the IP of the domain NIC or the NIC itself in some configuration.

$mgmtNetProfile = Get-NetConnectionProfile | where {$_.NetworkCategory -eq "DomainAuthenticated" }  # Assuming only one NIC is domain joined.
$mgmtNetIpAddress = Get-NetIPAddress -InterfaceIndex $mgmtNetProfile.InterfaceIndex -AddressFamily IPv4

Monday, August 19, 2013

Hyper-V WMI v2 porting guide

Ben Armstrong of the Hyper-V team just released (on the TechNet Wiki) a v2 namespace porting guide.

To all of my DevOps and developer friends out there, this is a highly useful guide.  Because if you have not noticed, moving from the v1 namespace to the v2 is not a simple change of the namespace.

And if you have not heard yet, the v1 namespace is GONE with the 2012 R2 release.

So, spend some time over at the TechNet Wiki page;

http://social.technet.microsoft.com/wiki/contents/articles/19192.hyper-v-wmi-v2-porting-guide.aspx

and then go over to Taylor Brown’s blog and check his updates of his v1 namespace examples to the v2 namespace:

http://blogs.msdn.com/b/taylorb/

Thursday, July 25, 2013

Disabling the BIN save state file on Hyper-V

This is a follow-up to my post: http://itproctology.blogspot.com/2013/07/the-forgotten-bin-element-in-hyper-v.html

Over time I have seen lots of posts from folks wanting to turn this off.

Well, that became possible with Hyper-V 2012. And actually is totally hidden, you might not know you are turning it off.

First, on the previous post I mentioned why the BIN (as I refer to them as the save state file) exist in the first place.

So, what if you turn them off?

Well, you turn them off and you lose the protection they offer. The safety net if you like. Think about that, consider the risk.  I did my job and warned you.

Before we jump in and disable it let's look at the settings option related to it first.

Per this post by Ben Armstrong this is rather simple; http://blogs.msdn.com/b/virtual_pc_guy/archive/2012/03/26/option-to-remove-bin-files-with-hyper-v-in-windows-8.aspx

Set-VM -AutomaticStopAction Save

This is the default and what you get without thinking. The safety net is on.

Set-VM -AutomaticStopAction ShutDown

This will cause Hyper-V to attempt clean shut down of the VM or click it off if it can't

Set-VM -AutomaticStopAction TurnOff

This will just click off your VMs, and give you that wonderful "why did I not shutdown cleanly" dialog later on.

According to Ben’s post; if you set either ShutDown or TurnOff, Hyper-V no longer creates the BIN file as a placeholder.

Now, if you take a snapshot of a running VM, you get one as a part of the snapshot (it is the actual saved memory state, not a placeholder). But it won't be there from the moment you turn on your VM.

In case you didn’t know how to use Set-VM: Get-VM –Name “Foo” | Set-VM –AutomaticStopAction ShutDown

 

Now, what if you want something a bit more useful, or you have bunches of VMs?

If you are using SCVMM:

Import-Module virtualmachinemanager

$prefix = Read-Host "Enter prefix to search on"

$vms = get-scvirtualmachine | where {$_.name -match $Prefix}

foreach ($vm in $vms) {
    # check if its status is clean in VMM, and clear it if not
    if ($vm.Status -eq "UpdateFailed") {Repair-SCVirtualMachine -VM $vm -Dismiss}
    if ($vm.VirtualMachineState -eq "Running") {Stop-SCVirtualMachine -VM $vm -Shutdown}

    # wait for the darn thing to cleanly shut down
    Do {Start-Sleep 30} until ($vm.VirtualMachineState -eq "PowerOff")
    if ($vm.StopAction -ne "ShutdownGuestOS"){Set-SCVirtualMachine -VM $vm -StopAction ShutdownGuestOS}

    if ($vm.StartAction -ne "TurnOnVMIfRunningWhenVSStopped"){Set-SCVirtualMachine -VM $vm -StartAction TurnOnVMIfRunningWhenVSStopped}

}

With the Hyper-V cmdlets the script would be changed very little.

If you are using Hyper-V cmdlets:

$prefix = Read-Host "Enter prefix to search on"

$vms = get-vm | where {$_.name -match $Prefix}

foreach ($vm in $vms) {
    if ($vm.State -eq "Running") {Stop-VM -VM $vm}

    # wait for the darn thing to cleanly shut down
    Do {Start-Sleep 30} until ($vm.State -eq "Off")
    if ($vm.AutomaticStopAction -ne "ShutDown"){vm | set-vm -AutomaticStopAction ShutDown}

    if ($vm.AutomaticStartAction -ne "StartIfRunning"){$vm | set-vm -AutomaticStartAction StartIfRunning}

}

SCVMM UR3 causes VMM Service to crash on Placement

I am sharing this because it burned me, and why should it burn anyone else.

This should have the sub-title of: “you need to read the release KB articles in deep detail” or “just don’t install Update Rollup 1 in the first place and you will be happier”.

I recently jumped straight into Update Rollup 3 for SCVMM 2012 SP1.  Because I had reported some bugs and the fixes were in there.

So, I downloaded the update rollup and I applied it to my VMM Console and to my VMM Server.

I then pushed out new agents to my remote Library Server and my Hyper-V Servers.  All was good.  Or so I thought.

I then deployed a Service Template.

During the time when SCVMM was sorting out where to place the VMs in my Service the VMM Service crashed.  Okay, so I tried again.  (not to expect a different result but to pay attention to figure out what was going wrong).

In the event log of the SCVMM Server I found the following message:

Log Name:      Application

Source:        Windows Error Reporting

Date:          7/24/2013 12:15:47 PM

Event ID:      1001

Task Category: None

Level:         Information

Keywords:      Classic

User:          N/A

Computer:      beSCVMM.brianeh.local

Description:

Fault bucket , type 0

Event Name: VMM20

Response: Not available

Cab Id: 0

Problem signature:

P1: vmmservice

P2: 3.1.6018.0

P3: Engine.Placement

P4: 3.1.6027.0

P5: M.V.E.P.C.VMDCConversionHelper.GetVMDCPrecheckResources

P6: System.MissingMethodException

P7: bf35

P8:

P9:

P10:

These files may be available here:

Analysis symbol:

Rechecking for solution: 0

Report Id: 711cf4e8-f495-11e2-9404-00155d289b00

Report Status: 262144

Hashed bucket:

Event Xml:

<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">

  <System>

    <Provider Name="Windows Error Reporting" />

    <EventID Qualifiers="0">1001</EventID>

    <Level>4</Level>

    <Task>0</Task>

    <Keywords>0x80000000000000</Keywords>

    <TimeCreated SystemTime="2013-07-24T19:15:47.000000000Z" />

    <EventRecordID>5184</EventRecordID>

    <Channel>Application</Channel>

    <Computer>beSCVMM.brianeh.local</Computer>

    <Security />

  </System>

  <EventData>

    <Data>

    </Data>

    <Data>0</Data>

    <Data>VMM20</Data>

    <Data>Not available</Data>

    <Data>0</Data>

    <Data>vmmservice</Data>

    <Data>3.1.6018.0</Data>

    <Data>Engine.Placement</Data>

    <Data>3.1.6027.0</Data>

    <Data>M.V.E.P.C.VMDCConversionHelper.GetVMDCPrecheckResources</Data>

    <Data>System.MissingMethodException</Data>

    <Data>bf35</Data>

  </EventData>

</Event>

So, I removed UR3 (the VMM Server KB…510).  I removed the hosts and remote library server from vmm management and added them back.  I fixed up all of my templates (Export them and Import them do fix them quickly).

I opened a case.

In the end, what was the root problem?   I didn’t uninstall Update Rollup 1.

Seriously?

Come to find out, buried in the details of this KB: http://support.microsoft.com/kb/2802159 is the installation information that Update Rollup 1 for SCVMM should be uninstalled manually prior to installing Update Rollup 2 (or any following Update Rollup).

Personally, I never read that particular article prior to installing UR2.  So I never knew to install UR1.  And, it is highly unusual to have to manually uninstall an Update Rollup prior to adding a second.

So, I then uninstalled UR1.  I re-applied UR2.  Then I installed UR3.  And all was happy.

Now, one easy way to check for this: 

If you select About from the ribbon of the SCVMM console you will see a version.  If you have UR3 installed it should be 3.1.6027.0 

If you have UR2 installed it should be 3.1.6020.0 

If you never manually uninstalled UR1 it will remain at 3.1.6018.0 after applying UR2 or UR3.