Monday, December 22, 2014

Mini-Orca: Getting Product Name and Code from an MSI

Was poking around the script source for the DSC package resource and found this nice way to get the product name and code for an MSI.  Before this I’d been using Orca to load the file and look at its properties.  This way looks much nicer.

$sig = @'

[DllImport("msi.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)]

private static extern UInt32 MsiOpenPackageW(string szPackagePath, out IntPtr hProduct);

 

[DllImport("msi.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)]

private static extern uint MsiCloseHandle(IntPtr hAny);

 

[DllImport("msi.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)]

private static extern uint MsiGetPropertyW(IntPtr hAny, string name, StringBuilder buffer, ref int bufferLength);

 

private static string GetPackageProperty(string msi, string property)

{

    IntPtr MsiHandle = IntPtr.Zero;

    try

    {

        var res = MsiOpenPackageW(msi, out MsiHandle);

        if (res != 0)

        {

            return null;

        }

           

        int length = 256;

        var buffer = new StringBuilder(length);

        res = MsiGetPropertyW(MsiHandle, property, buffer, ref length);

        return buffer.ToString();

    }

    finally

    {

        if (MsiHandle != IntPtr.Zero)

        {

            MsiCloseHandle(MsiHandle);

        }

    }

}

public static string GetProductCode(string msi)

{

    return GetPackageProperty(msi, "ProductCode");

}

   

public static string GetProductName(string msi)

{

    return GetPackageProperty(msi, "ProductName");

}

'@

$MsiTools = Add-Type -PassThru -Namespace Microsoft.Windows.DesiredStateConfiguration.PackageResource `

    -Name MsiTools -Using System.Text -MemberDefinition $sig

 

$MsiTools::GetProductName("C:\SharePointPreReqs\sqlncli.msi")

### Result: Microsoft SQL Server 2012 Native Client

 

$MsiTools::GetProductCode("C:\SharePointPreReqs\sqlncli.msi")

### Result: {49D665A2-4C2A-476E-9AB8-FCC425F526FC} 

 

Wednesday, December 17, 2014

Get the Domain Given a SecurityIdentifier (SID)

Somebody asked how to get the domain name, given the SID of an object.  There’s at least a couple of ways. 

One uses the Get-ADDomain command in the ActiveDirectory module.  This works because the Identity parameter accepts the domain SID (nice).

Another way is to use the Translate method of the SecurityIdentifier class to translate to an NTAccount which has the account name in the format of Domain\Account.

### Create a new Security Identifier Object

$sid = New-Object System.Security.Principal.SecurityIdentifier "S-1-5-21-2627401586-940742709-677887653-1013"

 

### Get the AD Domain for that SID

Get-ADDomain -Identity $sid.AccountDomainSid

 

### Tranlsate to an NTAccount (REDMOND\FOO)

$sid.Translate([System.Security.Principal.NTAccount])

 

Wednesday, December 03, 2014

Using WMI and XML to Read Hyper-V Key-Value Pair Data

Here is the follow-up to the post about using DSC to set a key-value pair item for Hyper-V and its integration services.

The code sample below shows how to use WMI and XML to read the specific item from the key-value pair data.

The only real trick to this is to create a string that can be cast to XML, which just means creating the root node (kvpItems in the sample below) then inserting the string we get from WMI.

The next part is to use XPath to pick out just the item we need.  Having worked with FIM long enough I have developed a liking to XPath, but could have just as easily skipped XML and XPath and gone with a quick –like operator (though it wouldn’t be a nice).

Here’s the sample code:

###

### Get a VM

### then get its Key-Value Pair items

### then put them into an XML DOM

### then use XPath to find a specific key-value pair

###

$vmName = 'HoofHeartedVM'

do{

    Write-Verbose "$(Get-Date) Waiting for the FIM Service to reach the started state."

 

    $vm  = Get-WmiObject -Namespace root\virtualization\v2 -Class Msvm_ComputerSystem -Filter "ElementName='$vmName'"

    $kvp = Get-WmiObject -Namespace root\virtualization\v2 -Query "Associators of {$Vm} Where AssocClass=Msvm_SystemDevice ResultClass=Msvm_KvpExchangeComponent"

 

    $kvpItems = [xml]"<KvpItems>$($kvp.GuestIntrinsicExchangeItems)</KvpItems>"

    $kvpItem  = Select-Xml -Xml $kvpItems -XPath "/KvpItems/INSTANCE[PROPERTY/VALUE[.='FimServiceStatus'] and PROPERTY/VALUE[.='Running']]"

    Start-Sleep -Seconds 60

}

until($kvpItem)

 

Using DSC to Communicate with the Hyper-V Host from the Guest

There are some great posts describing how to use Hyper-V to trade data between the Hyper-V Host and the VM without relying on network connectivity.  This comes in handy when a VM is not available on the network, WinRM is not available, or security is just a little too tight for comfort.

Here’s some of those posts:

In my environment I want the Hyper-V host to know when a VM reaches the state where the FIM Service is running.  They way I do it is to use DSC to create a registry key.  Pretty simple.

I’ll follow-up with the script to consume the Key-Value pairs on the Hyper-V host.

configuration SampleHypervKvpConfiguration

{

    node (hostname)

    {

        Service FimService

        {

            Name     = "FimService"

            State    = "Running"

        }

 

        Registry HypervKvpForFimService

        {

            Ensure    = "Present"

            Key       = "HKLM:\SOFTWARE\Microsoft\Virtual Machine\Auto"

            ValueName = "FimServiceStatus"

            ValueData = "Running"

            DependsOn = '[Service]FimService'

        }

    }

}

 

SampleHypervKvpConfiguration -OutputPath $env:temp\SampleHypervKvpConfiguration

 

Start-DscConfiguration -Path $env:temp\SampleHypervKvpConfiguration -Verbose -Wait

 

Tuesday, December 02, 2014

Solve the 'Circular DependsOn exists' Error

The blog title is a suggestion posted on Connect for PowerShell:

Solve the 'Circular DependsOn exists' Error

The DependsOn parameter enables PowerShell Desired State Configuration (DSC) to resolve references in the configuration and order them properly.  This works quite well in my experience building a DSC configuration for FIM but there are a couple cases in FIM that break this functionality:

  • Set objects that refer to each other
  • Forest Configuration objects where the forests trust each other

In pre-DSC days I would just solve this by doing multiple passes to order them properly.  Seems like a simple enough ask but my guess is that the existing DSC resources don’t run into this problem yet because they don’t represent objects with circular dependencies (lucky me). 

My current workaround is just to exclude the properties that cause the problem, which for now results in a broken configuration.  My next step is to cheat by using a Script resource in my DSC configuration to fix up the items that required hacking.

At the end of the day I really can’t complain.  I’ve generated a 40,000 line DSC script using thousands of FIM objects, resulting in a 6MB MOF file.  At this scale I was expecting something to tip over but so far am pretty impressed.  Now, time to run that MOF file through the LCM, what could possibly go wrong?

Monday, December 01, 2014

Having Too Much to DependsOn

In building a Desired State Configuration document for a FIM Service deployment I’ve come across a limit when using the DependsOn parameter:

StrongConnect : DependsOn link exceeded max depth limitation '1024'.

This happened when I had a configuration item that depended on more than 1024 other items.  In this case, it was a FIM Set object with thousands of ExplicitMember values.  The configuration is valid in FIM, so the resulting DSC configuration I’d generated was what I wanted but I guess past the limits for what DependsOn was intended for.

The workaround was just to omit the items, which could cause the configuration to fail late if the ExplicitMember items don’t actually exist in the FIM Service when the configuration runs.  For now I might just create those items out-of-band from DSC.

Tuesday, November 25, 2014

Counting Members in a FIM Set

Troubleshooting a strange configuration issue today and am trying to figure out why performance of references is less than awesome.

This particular query helped narrow down the problem.  For some reason I have a bunch of Sets with huge numbers of explicit members.  The sample is a good illustration of getting the data out of the FIM Service, then querying it and formatting it using PowerShell.  In some cases you can define a better query using XPath against the FIM Service but often it is easier to just do it in PowerShell.

Here’s the query to find the sets:

 

### Get all the Sets

Export-FIMConfig -OnlyBaseResources -CustomConfig "/Set" |

### Convert to PSObjects (easier to deal with than FIM Export Objects)

Convert-FimExportToPSObject |

### Get just the Sets with ExplicitMember

Where-Object ExplicitMember |

### Sort by the count of members

Sort-Object {$_.ExplicitMember.Count} -Descending  |

### Output as a nice table

Format-Table DisplayName, @{Name='ExplicitMemberCount';Expression={$_.ExplicitMember.Count}} -AutoSize

 

<#

 

DisplayName                           ExplicitMemberCount

-----------                           -------------------

Administrators                                          1

Password Reset Objects Set                              4

Crazy Set One                                      200000

FIM Support Tier One                                    7

FIM Programmatic Access                                 4

 

#>

 

 

 

Thursday, November 13, 2014

Microsoft Acquires Aorato

Very interesting news today from Microsoft:

Active Directory Team Blog: Microsoft Acquires Aorato

This is interesting because it shows investment in the on-premises Active Directory (we’re already a tonne of investment in Azure AD, no complaints there).

We’re also seeing AD investments in the new Privileged Access Management (PAM) functionality, which also has ties into the next version of FIM (MIM).  MIM is not strictly required for the PAM functionality, but it augments it by adding extra policy enforcement.  The TTL nature of the group membership completely lives in AD.

It’s happened too often now that acquisitions get thrown into the FIM solution suite and don’t get truly integrated into AD or Windows Server or even FIM.  Looking forward to seeing where the Aorato technology lands; my preference would be for it to be baked into AD or a feature of the AD role.

Wednesday, November 12, 2014

Install SharePoint Foundation using PowerShell

Found this little stash of scripts (in the zip) on TechNet recently:

Install SharePoint Foundation 2010 by using Windows PowerShell

Having just finished the 2014 MVP Summit and getting my head full of PowerShell Desired State Configuration I thought I would be able to install SharePoint Foundation using DSC.

NOTE: I hope to post later on how to install the SharePoint prerequisites using the DSC Package Resource.

For now, here is the snippet for installing SharePoint Foundation using the DSC Package Resource:

configuration SharePoint

{

    node (hostname)

    {

        <#

        This is just a snippet of a larger configuration that I'm working on

        In the larger configuration I am installing of the SharePoint prerequisites, but still working on that

        I've left the 'DependsOn' parameter in to demonstrate how you would make the SharePoint install happen after its prereqs

        #>

        Package InstallSharePointFoundation

        {

            Ensure             = "Present"

            Name               = "Microsoft SharePoint Foundation 2013 Core"

            Path               = "C:\Temp\SharePointFoundation2013\Setup.exe"

            Arguments          = "/config C:\Temp\SharePointFoundation2013\files\setupsilent\config.xml"

            ProductID          = "90150000-1014-0000-1000-0000000FF1CE"

            ReturnCode         = 8

            DependsOn          = @(

                "[Script]AppFabricUpdate"

                "[WindowsFeature]ApplicationServer"

                "[WindowsFeature]WebWebServer"

                "[WindowsFeature]NetFramework45Full"

                "[Package]WcfDataServices5"

                "[Package]WcfDataServices56"

                "[xPendingReboot]BeforeSharePointInstall"

            )

        }

    }

}

 

SharePoint -OutputPath c:\temp\SharePoint

 

Start-DscConfiguration -Verbose -Wait -Path c:\temp\SharePoint

 

Monday, November 10, 2014

Microsoft Identity Manager Preview

The upcoming major release of FIM (already renamed to MIM) now has a preview available for download.  The Microsoft Connect site requires an agreement so expect some prompts and identity detail sharing:

https://connect.microsoft.com/site433/

To get an overview of what the preview includes, you can view the recorded TechEd Europe session on Channel 9:

Microsoft Identity Manager vNext Overview

Tuesday, October 28, 2014

Handling Reboots in a DSC Configuration

When automating a server configuration you’ll eventually run into the scenario where a reboot is required before a component can be installed.  In Desired State Configuration this can be handled with the xPendingReboot PowerShell Module (from the DSC Resource Kit).  Ed Wilson did a nice write-up of this, including some of the pre-reqs here: Use PowerShell DSC to Check Pending Reboot.  

I had to make a couple of changes to his sample before really shooting myself in the foot.  Turns out the first thing DSC does after rebooting is resume the configuration, which in my simplified demo case just told the LCM to go ahead and reboot again.  It took me a while to break that reboot loop (nice one, doofus).

In the sample below I have used Start-Sleep to give you a fighting chance to stop the cycle of reboots Winking smile.  The sample below WILL reboot your server, so don’t do it to your friends or users.

configuration Reboots

{

    # Get this from TechNet Gallery

    Import-DsCResource -ModuleName xPendingReboot

 

    node (hostname)

    {     

        LocalConfigurationManager

        {

            # This is false by default

            RebootNodeIfNeeded = 'true'

        }

       

        Script TestReboot

        {

            GetScript  = { return 'foo'}

            TestScript = { return $false}

            SetScript  = {

                # Insert a delay before the reboot, otherwise the machine will be stuck in a reboot cycle

                Start-Sleep -Seconds (5*60)

 

                # Setting the global:DSCMachineStatus = 1 tells DSC that a reboot is required

                $global:DSCMachineStatus = 1

            }

        }

 

        # Reboot if pending

        xPendingReboot RebootCheck1

        {

            Name = "RebootCheck1"

        }

 

    }

}

 

Set-Location c:\temp

 

Reboots

 

Set-DscLocalConfigurationManager -Path .\Reboots -Verbose

 

Start-DscConfiguration -Verbose -wait -Path .\Reboots -Force