Get-DSCConfigurationFromSystem.psm1

#region General
Function Get-IsAdmin
{
    $user = [Security.Principal.WindowsIdentity]::GetCurrent()
    If((New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator))
    {
        $true
    }
    Else
    {
        $false
    }
}
#endregion

#region Build-DSCConfigurationFromRegistry
Function Replace-Properties
{
    Param
    (
        
        [Parameter(Mandatory=$true)]
        $Property
    )
    $Property = $Property.tostring()  
    $Property = $Property.replace('HKLM:','HKEY_Local_Machine')
    $Property = $Property.replace('HKCU:','HKEY_Current_User')
    $Property = $Property.replace('MultiString','REG_MULTI_SZ')
    $Property = $Property.replace('ExpandString','REG_EXPAND_SZ')
    $Property = $Property.replace('String','REG_SZ')
    $Property = $Property.replace('Binary','REG-BINARY')
    $Property = $Property.replace('DWord','REG_DWORD')
    $Property = $Property.replace('QWord','REG_QWORD')

    Return $Property
} #end Function

Function Get-RegistryKeyPropertiesAndValues
{
    Param
    (
        [Parameter(Mandatory=$true)]
        [string]$path
    )
    $array = @()
    
    (Get-ItemProperty "Registry::$path").PSObject.Properties | Where-Object {$_.Name -notlike 'PS*'} | Select-Object Name, Value | % {
        
        $Key = Replace-Properties -Property $path

        If ($_.Name -eq '(default)') 
        {
            If (-not $IgnoreDefault)
            {
                $ValueType = 'REG_SZ'
                $ValueData = (Get-Item "Registry::$path").GetValue("$($_.name)",$False, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
                $Property = New-Object psobject -Property @{'Key' = $Key; 'ValueName' = $_.Name; 'ValueData' = $ValueData; 'ValueType' = $ValueType}
                $array += $Property
            }
        }
        Else
        {
            $Type = (Get-Item "Registry::$path").GetValueKind($_.Name)
            $ValueType = Replace-Properties -Property $Type
            $ValueData = (Get-Item "Registry::$path").GetValue("$($_.name)",$False, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
            $Property = New-Object psobject -Property @{'Key' = $Key; 'ValueName' = $_.Name; 'ValueData' = $ValueData; 'ValueType' = $ValueType}
            $array += $Property
        }
    }    
    
    Return $array
} #end Function

Function Get-ValuesInRegKey
{
    Param
        (
            [Parameter(Mandatory=$true)]
            [string]$path
        )

    Get-ChildItem $path | ForEach-Object {

        Get-RegistryKeyPropertiesAndValues -path $_

    }
} #end Function

Function Get-ValuesInRegKeyRecurse
{
    Param
        (
            [Parameter(Mandatory=$true)]
            [string]$path
        )

    Get-ChildItem $path -Recurse | ForEach-Object {

        Get-RegistryKeyPropertiesAndValues -path $_

    }
} #end Function

Function Get-DSCConfigurationFromRegistry
{
    <#
            .SYNOPSIS
            This function converts a registry key and its values to the DSC Registry Resource format. If you want, it does this recursively
            .PARAMETER RegPath
            Path to the registry key. E.g. HKLM:\SOFTWARE\SomeSoftware
            .PARAMETER ExportPath
            Path to the file where the converted data will be stored. The data will be appended to the file if the file already exists
            .PARAMETER ForceValueReplacement
            Adds 'Force = $True' for each value in the output so that DSC will replace the data of the value if the value already exists. For more information have a look at technet: https://technet.microsoft.com/en-us/library/dn282133.aspx
            .PARAMETER IgnoreDefault
            If parameter is set, the default values will be ignored and won't show up in you DSC registry configuration
            .INPUTS
            This function does not allow any input
            .OUTPUTS
            This function exports data to a file. No output on the console.
            .NOTES
            Source: https://github.com/DominikBritz
    #>


    [CmdletBinding()]
    PARAM
    (
        [Parameter(Position=0,Mandatory=$True)]
        [ValidateScript({Test-Path $_})]
        $RegPath,
    
        [Parameter(Position=1,Mandatory=$True)]
        [ValidateNotNullOrEmpty()]
        $ExportPath,
    
        [switch]
        $Recurse,

        [switch]
        $ForceValueReplacement,
    
        [switch]    
        $IgnoreDefault 
    )

    #region Variables
    Set-Variable $IgnoreDefault -Scope Script
    #endregion


    $output = @()

    If ($Recurse) {$output += Get-ValuesInRegKeyRecurse -path $RegPath}
    If (-not $Recurse) {$output += Get-ValuesInRegKey -path $RegPath}

    If ($ForceValueReplacement)
    {
        ForEach ($Item in $output) {
            $Config = @"
Registry $(Join-Path $Item.Key $Item.ValueName){
    Ensure = "Present"
    Key = "$($Item.Key)"
    ValueName = "$($Item.ValueName)"
    Force = `$True
    ValueData = "$($Item.ValueData)"
    ValueType = "$($Item.ValueType)"
}
"@

            Try
            {
                $Config >> $ExportPath
            }
            Catch
            {
                Throw $_
            } #end Catch
        } #end ForEach
    } #end If

    Else
    {
        ForEach ($Item in $output) {
            $Config = @"
Registry $(Join-Path $Item.Key $Item.ValueName){
    Ensure = "Present"
    Key = "$($Item.Key)"
    ValueName = "$($Item.ValueName)"
    ValueData = "$($Item.ValueData)"
    ValueType = "$($Item.ValueType)"
}
"@

            Try
            {
                $Config >> $ExportPath
            }
            Catch
            {
                Throw $_
            } #end Catch
        } #end ForEach
    } #end Else



} #end Function

#endregion

#region Get-DSCConfigurationFromWindowsFeature

Function Get-DSCConfigurationFromWindowsFeature 
{    
    <#
            .SYNOPSIS
            This function converts information of the windows features of the local system to the DSC WindowsFeature Resource format.
            .PARAMETER ExportPath
            Path to the file where the converted data will be stored. The data will be appended to the file if the file already exists
            .PARAMETER IncludeAllSubFeature
            Adds 'IncludeAllSubFeature = $True' for each value in the output. From Technet: Set this property to $true to ensure the state of all required subfeatures with the state of the feature you specify with the Name property
            .PARAMETER LogPath
            Indicates the path to a directory where you want the resource provider to log the operation. Each feature gets an own log file.
            .PARAMETER Credential
            Indicates the credentials to use to add or remove the role or feature
            .INPUTS
            This function does not allow any input
            .OUTPUTS
            This function exports data to a file. No output on the console.
            .NOTES
            Source: https://github.com/DominikBritz
    #>

    [CmdletBinding()]
    PARAM
    (
        [Parameter(Position=0,Mandatory=$True)]
        [ValidateNotNullOrEmpty()]
        $ExportPath,
        
        [switch]
        $IncludeAllSubFeature,

        [string]
        $LogPath,

        [PSCredential]
        $Credential
    )

    If (!(Get-IsAdmin)) {Throw 'You have to work with this function from an elevated powershell window'}

    If (!(Test-Path $LogPath)) 
    {
        Try
        {
            New-Item -Path $LogPath -ItemType Directory -Force -ErrorAction Stop
        }
        Catch
        {
            Throw $_
        }
    
    }

    $dism = Dism.exe /Online /Get-Features /Format:List /english | Where-Object {$_}        

    $f = $dism[4..($dism.length-2)]
    $Features = for($i=0; $i -lt $f.length;$i+=2)
    {
        $tmp = $f[$i],$f[$i+1] -replace '^([^:]+:\s)'
                
        New-Object PSObject -Property @{
            Name = $tmp[0]
            State = $tmp[1]
        }
    }

    foreach($item in $Name)
    {
        $Features | Where-Object {$_.Name -like $item -AND $_.State -like $State}
    }

    Foreach ($Feature in $Features)
    {
        If ($Feature.State -eq 'Enabled') 
        {
            $DSCState = 'Present'
        }
        Else {$DSCState = 'Absent'}        

        $Config = @"
WindowsFeature $($Feature.Name)
{
    Name = "$($Feature.Name)"
    Ensure = "$DSCState"
}
"@

        If ($IncludeAllSubFeature) {$Config += "`n IncludeAllSubFeature = `$True"}
        If ($LogPath) {$Config += "`n LogPath = $(Join-Path $LogPath $($Feature.Name))"}
        Try
        {
            $Config >> $ExportPath
        }
        Catch
        {
            Throw $_
        } #end Catch
    } #end ForEach
} #end Function
#endregion

#region Get-DSCConfigurationFromServices
Function Get-DSCConfigurationFromServices
{
    <#
        .SYNOPSIS
        This function converts the properties of a Windows service into the DSC service format
        .PARAMETER ExportPath
        Path to the file where the converted data will be stored. The data will be appended to the file if the file already exists
        .INPUTS
        This function does not allow any input
        .OUTPUTS
        This function exports data to a file. No output on the console.
        .NOTES
        Source: https://github.com/DominikBritz
    #>

    [CmdletBinding()]
    PARAM
    (
        [Parameter(Position=0,Mandatory=$True)]
        [ValidateNotNullOrEmpty()]
        $ExportPath
    )
$array = @()
Get-Service * | ForEach-Object {
$Service = $_
$Credential = $Null

$StartupType = (Get-WmiObject -Class Win32_Service -Property StartMode -Filter "Name='$($Service.Name)'").StartMode
If ($StartupType -eq 'Auto')
{
    $StartupType = 'Automatic'
}

$StartName = (Get-WmiObject -Class Win32_Service -Property StartName -Filter "Name=`"$($Service.Name)`"").StartName
Switch ($StartName) {
'LocalSystem' {$StartName = 'LocalSystem'; break}
'NT Authority\LocalService' {$StartName = 'LocalService'; break}
'NT AUTHORITY\NetworkService' {$StartName = 'NetworkService'; break}
default {$Credential = $StartName}
}

If ($Credential) {
$Config = @"
Service $($Service.Name)
{
    Name = "$($Service.Name)"
    Credential = "$Credential"
    StartupType = "$StartupType"
    State = "$($Service.Status)"
}
"@

}
Else{
$Config = @"
Service $($Service.Name)
{
    Name = "$($Service.Name)"
    BuiltInAccount = "$StartName"
    StartupType = "$StartupType"
    State = "$($Service.Status)"
}
"@

}
Try
{
    $Config >> $ExportPath
}
Catch
{
    Throw $_
}

}

}
#endregion


Export-ModuleMember -Function Get-DSCConfigurationFromRegistry
Export-ModuleMember -Function Get-DSCConfigurationFromWindowsFeature
Export-ModuleMember -Function Get-DSCConfigurationFromServices