DscBaseline.psm1
function Invoke-DscBaseline { <# .SYNOPSIS Creates DSC configurations based on the configuration of the current system. .DESCRIPTION This PowerShell module was created to expedite the adoption of Microsoft Desired State Configuration (DSC) for configuration management. Building these configuration files by hand takes far too long and lacks the benfits of a programmatic solution. DscBaseline covers common DSC modules and creates configuration files based on the system where it is launched. Areas covered include: Security Policy, Audit Policy, Service Configurations, Network. Some Group Policy settings can be converted to a Registry Setting policy though this specific functionality should be considered experimental. .EXAMPLE Invoke-DscBaseline -Folder D:\WorkingFolder\ .EXAMPLE Invoke-DscBaseline -Folder D:\WorkingFolder\ -TryGroupPolicy -Verbose .LINK https://github.com/phbits/DscBaseline #> [OutputType([System.Collections.Hashtable])] [CmdletBinding()] param ( [parameter(Mandatory=$false)] [ValidateScript({Test-Path -Path $_ -PathType Container})] [String] # Folder to save files. $Folder = (Get-Location).Path , [Parameter(Mandatory=$false)] [Switch] # EXPERIMENTAL: Build registry configs from Group Policy settings. $TryGroupPolicy ) $i = 0 do { switch($i) { 0 { Write-Verbose -Message 'Verify elevated command prompt is being used.' $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) $isCmdElevated = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) if($isCmdElevated -eq $false) { $userMessage = "`n Invoke-DscBaseline is not running in an elevated command prompt.`n" + ` " Some configurations will fail to be created by this module.`n" + ` " Reference: https://docs.microsoft.com/en-us/powershell/scripting/windows-powershell/starting-windows-powershell#with-administrative-privileges-run-as-administrator`n" + ` " Continue? [Y/N]" $userInput = Read-Host -Prompt $userMessage if($null -eq $userInput) { $i = 100 } else { if($userInput.ToString().ToLower().Trim().StartsWith('y') -eq $false) { $i = 100 } } } } 1 { Write-Verbose -Message 'Verify AuditPol.exe can run.' $auditPolTest = Test-AuditPol if($auditPolTest -eq $false) { $userMessage = "`n Test of auditpol.exe failed. This likely means the current user ($($env:USERDOMAIN)\$($env:USERNAME))`n" + ` " must be granted the `'Manage Auditing and Security Log`' User Rights Assignment.`n" + ` " Reference: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/manage-auditing-and-security-log`n" + ` " Continue? [Y/N]" $userInput = Read-Host -Prompt $userMessage if($null -eq $userInput) { $i = 100 } else { if($userInput.ToString().ToLower().Trim().StartsWith('y') -eq $false) { $i = 100 } } } } 2 { if($TryGroupPolicy) { Write-Verbose -Message 'Checking if system is domain joined' if((Get-CimInstance -ClassName Win32_ComputerSystem).PartOfDomain) { $userMessage = "`n DscBaseline works best on stand alone systems (i.e. non-domain-joined).`n" + ` " Running this on a domain joined system may produce imcomplete Group Policy results.`n" + ` " Continue? [Y/N]" $userInput = Read-Host -Prompt $userMessage if($null -eq $userInput) { $i = 100 } else { if($userInput.ToString().ToLower().Trim().StartsWith('y') -eq $false) { $i = 100 } } } } } 3 { Write-Verbose -Message 'Generating Audit Policy DSC Configuration' $auditPolicyDscConfig = Get-DscBaselineAuditPolicy -Folder $Folder Write-Verbose -Message " $($auditPolicyDscConfig)" } 4 { Write-Verbose -Message 'Generating Security Policy DSC Configuration' [hashtable] $securityPolicyDscConfig = Get-DscBaselineSecurityPolicy -Folder $Folder $securityPolicyDscConfig.Keys | ForEach-Object{ Write-Verbose -Message " $($securityPolicyDscConfig[$_])" } } 5 { if($TryGroupPolicy) { Write-Verbose -Message 'Generating Group Policy DSC Configuration' $groupPolicyDscConfig = Get-DscBaselineGroupPolicy -Folder $Folder Write-Verbose -Message " $($groupPolicyDscConfig)" } } 6 { Write-Verbose -Message 'Generating Services DSC Configuration' $servicesDscConfig = Get-DscBaselineServices -Folder $Folder Write-Verbose -Message " $($servicesDscConfig)" } 7 { Write-Verbose -Message 'Generating Network DSC Configuration' $networkDscConfig = Get-DscBaselineNetwork -Folder $Folder Write-Verbose -Message " $($networkDscConfig)" } 8 { Write-Verbose -Message 'Generating Proxy Settings DSC Configuration' $proxySettingsDscConfig = Get-DscBaselineProxySettings -Folder $Folder Write-Verbose -Message " $($proxySettingsDscConfig)" } 9 { Write-Verbose -Message 'Finished creating configuration files.' Write-Verbose -Message 'To show newly created configuration files run:' Write-Verbose -Message " Get-ChildItem -Path $($Folder) -File -Filter `"DscBaseline*.ps1`"" } 10{ Write-Verbose -Message 'Generating ApplyDscConfig.ps1' $applyDscConfigFile = Join-Path $Folder -ChildPath 'ApplyDscConfig.ps1' [string[]] $applyDscConfigFileContents = @() $applyDscConfigFileContents += "# These commands can be used to apply DSC configuration files to a system.`n" $applyDscConfigFileContents += "# Prevent accidental launch." $applyDscConfigFileContents += "return [string] 'ACCIDENT_LAUNCH_PREVENTION_ApplyDscConfig.ps1'" $applyDscConfigFileContents += "`n# Install DSC modules. Only needed once." $applyDscConfigFileContents += "Install-Module AuditPolicyDsc" $applyDscConfigFileContents += "Install-Module NetworkingDsc" $applyDscConfigFileContents += "Install-Module PSDscResources" $applyDscConfigFileContents += "Install-Module SecurityPolicyDsc" $applyDscConfigFileContents += "`n# Reset the Local Configuration Manager (LCM)" $applyDscConfigFileContents += 'Reset-LcmConfiguration' $applyDscConfigFileContents += "`n# Convert configuration files to .mof (human readable to machine readable)" $dscConfigFiles = Get-ChildItem -Path $($Folder) -File -Filter "DscBaseline*.ps1" foreach($dscConfigFile in $dscConfigFiles) { $applyDscConfigFileContents += "& $($dscConfigFile.FullName) -Verbose" } $applyDscConfigFileContents += "`n# Prevent the system from rebooting after a configuration is applied." $applyDscConfigFileContents += 'Set-LcmSetting -RebootNodeIfNeeded $false -ConfigurationMode ApplyAndAutoCorrect -ActionAfterReboot ContinueConfiguration' $applyDscConfigFileContents += "`n# Add each .mof as a partial configuration." foreach($dscConfigFile in $dscConfigFiles) { $applyDscConfigFileContents += "Add-LcmPartialConfiguration -PartialName `'$($dscConfigFile.BaseName)`' -Description `'$($dscConfigFile.BaseName) Partial Configuration.`' -RefreshMode `'Push`' -Verbose" } $applyDscConfigFileContents += "`n# Publish the configurations." foreach($dscConfigFile in $dscConfigFiles) { $applyDscConfigFileContents += "Publish-DscConfiguration -Path $($dscConfigFile.FullName.SubString(0,$dscConfigFile.FullName.Length - 4)) -Verbose" } $applyDscConfigFileContents += "`n# Start DSC configuration process then get the resulting status." $applyDscConfigFileContents += 'Start-DscConfiguration -UseExisting -Verbose -Wait' $applyDscConfigFileContents += 'Get-DscConfigurationStatus | Format-List' $applyDscConfigFileContents += "`n# To see a detailed list of failed items." $applyDscConfigFileContents += 'Get-DscConfigurationStatus | Select-Object -ExpandProperty ResourcesNotInDesiredState' Out-File -FilePath $applyDscConfigFile -InputObject $applyDscConfigFileContents -Encoding ASCII -Force Write-Verbose -Message " $applyDscConfigFile" } default { $i = 100 } } $i++ }while($i -lt 100) [string[]] $configurationFiles = Get-ChildItem -Path $($Folder) -File -Filter "DscBaseline*.ps1" | ForEach-Object{ $_.FullName } [string] $applySettingsFile += Get-ChildItem -Path $($Folder) -File -Filter 'ApplyDscConfig.ps1' | ForEach-Object{ $_.FullName } return @{ 'ConfigurationFiles' = $configurationFiles; 'ApplySettingScript' = $applySettingsFile; } } # end function Invoke-DscBaseline |