source/Scripts/Configuration/Apply-STIGDirectSignOnExceptions.ps1 (288 lines of code) (raw):

[CmdletBinding(SupportsShouldProcess = $true)] param ( [Parameter(Mandatory = $false)] [Hashtable] $DynParameters ) [uri]$LGPOWebUrl = "https://www.microsoft.com/en-us/download/confirmation.aspx?id=55319" [string]$LogDir = "$env:SystemRoot\Logs\Configuration" [string]$ScriptName = "Apply-STIG-Exceptions" [string]$Log = Join-Path -Path $LogDir -ChildPath "$ScriptName.log" [string]$tempDir = Join-Path -Path $env:Temp -ChildPath $ScriptName #region Functions Function Get-InternetUrl { [CmdletBinding()] Param ( [Parameter(Mandatory = $true, Position = 0)] [uri]$Url, [Parameter(Mandatory = $true, Position = 1)] [string]$searchstring ) Begin { [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name $ProgressPreference = 'SilentlyContinue' } Process { Try { Write-Verbose "${CmdletName}: Now extracting download URL from '$Url'." $HTML = Invoke-WebRequest -Uri $Url -UseBasicParsing $Links = $HTML.Links $ahref = $null $ahref=@() $ahref = ($Links | Where-Object {$_.href -like "*$searchstring*"}).href If ($ahref.count -eq 0 -or $null -eq $ahref) { $ahref = ($Links | Where-Object {$_.OuterHTML -like "*$searchstring*"}).href } If ($ahref.Count -eq 1) { Write-Verbose "${CmdletName}: Download URL = '$ahref'" $ahref } Elseif ($ahref.Count -gt 1) { Write-Verbose "${CmdletName}: Download URL = '$($ahref[0])'" $ahref[0] } } Catch { Write-Error "${CmdletName}: Error Downloading HTML and determining link for download." Exit 1 } } End { } } Function Get-InternetFile { [CmdletBinding()] Param ( [Parameter(Mandatory = $true, Position = 0)] [uri]$Url, [Parameter(Mandatory = $true, Position = 1)] [string]$OutputDirectory, [Parameter(Mandatory = $false, Position = 2)] [string]$OutputFileName ) Begin { [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name } Process { $start_time = Get-Date If (!$OutputFileName) { Write-Verbose "${CmdletName}: No OutputFileName specified. Trying to get file name from URL." If ((split-path -path $Url -leaf).Contains('.')) { $OutputFileName = split-path -path $url -leaf Write-Verbose "${CmdletName}: Url contains file name - '$OutputFileName'." } Else { Write-Verbose "${CmdletName}: Url does not contain file name. Trying 'Location' Response Header." $request = [System.Net.WebRequest]::Create($url) $request.AllowAutoRedirect=$false $response=$request.GetResponse() $Location = $response.GetResponseHeader("Location") If ($Location) { $OutputFileName = [System.IO.Path]::GetFileName($Location) Write-Verbose "${CmdletName}: File Name from 'Location' Response Header is '$OutputFileName'." } Else { Write-Verbose "${CmdletName}: No 'Location' Response Header returned. Trying 'Content-Disposition' Response Header." $result = Invoke-WebRequest -Method GET -Uri $Url -UseBasicParsing $contentDisposition = $result.Headers.'Content-Disposition' If ($contentDisposition) { $OutputFileName = $contentDisposition.Split("=")[1].Replace("`"","") Write-Verbose "${CmdletName}: File Name from 'Content-Disposition' Response Header is '$OutputFileName'." } } } } If ($OutputFileName) { $wc = New-Object System.Net.WebClient $OutputFile = Join-Path $OutputDirectory $OutputFileName Write-Verbose "${CmdletName}: Downloading file at '$url' to '$OutputFile'." Try { $wc.DownloadFile($url, $OutputFile) $time = (Get-Date).Subtract($start_time).Seconds Write-Verbose "Time taken: '$time' seconds." if (Test-Path -Path $outputfile) { $totalSize = (Get-Item $outputfile).Length / 1MB Write-Verbose "${CmdletName}: Download was successful. Final file size: '$totalsize' mb" $OutputFile } } Catch { Write-Error "${CmdletName}: Error downloading file. Please check url." Exit 2 } } Else { Write-Error "${CmdletName}: No OutputFileName specified. Unable to download file." Exit 2 } } End { } } Function Update-LocalGPOTextFile { [CmdletBinding(DefaultParameterSetName = 'Set')] Param ( [Parameter(Mandatory = $true, ParameterSetName = 'Set')] [Parameter(Mandatory = $true, ParameterSetName = 'Delete')] [Parameter(Mandatory = $true, ParameterSetName = 'DeleteAllValues')] [ValidateSet('Computer', 'User')] [string]$scope, [Parameter(Mandatory = $true, ParameterSetName = 'Set')] [Parameter(Mandatory = $true, ParameterSetName = 'Delete')] [Parameter(Mandatory = $true, ParameterSetName = 'DeleteAllValues')] [string]$RegistryKeyPath, [Parameter(Mandatory = $true, ParameterSetName = 'Set')] [Parameter(Mandatory = $true, ParameterSetName = 'Delete')] [Parameter(Mandatory = $true, ParameterSetName = 'DeleteAllValues')] [string]$RegistryValue, [Parameter(Mandatory = $true, ParameterSetName = 'Set')] [AllowEmptyString()] [string]$RegistryData, [Parameter(Mandatory = $true, ParameterSetName = 'Set')] [ValidateSet('DWORD', 'String')] [string]$RegistryType, [Parameter(Mandatory = $false, ParameterSetName = 'Delete')] [switch]$Delete, [Parameter(Mandatory = $false, ParameterSetName = 'DeleteAllValues')] [switch]$DeleteAllValues, [string]$outputDir = "$TempDir", [string]$outfileprefix = $appName ) Begin { [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name } Process { # Convert $RegistryType to UpperCase to prevent LGPO errors. $ValueType = $RegistryType.ToUpper() # Change String type to SZ for text file If ($ValueType -eq 'STRING') { $ValueType = 'SZ' } # Replace any incorrect registry entries for the format needed by text file. $modified = $false $SearchStrings = 'HKLM:\', 'HKCU:\', 'HKEY_CURRENT_USER:\', 'HKEY_LOCAL_MACHINE:\' ForEach ($String in $SearchStrings) { If ($RegistryKeyPath.StartsWith("$String") -and $modified -ne $true) { $index = $String.Length $RegistryKeyPath = $RegistryKeyPath.Substring($index, $RegistryKeyPath.Length - $index) $modified = $true } } #Create the output file if needed. $Outfile = "$OutputDir\$Outfileprefix-$Scope.txt" If (-not (Test-Path -LiteralPath $Outfile)) { If (-not (Test-Path -LiteralPath $OutputDir -PathType 'Container')) { Try { $null = New-Item -Path $OutputDir -Type 'Directory' -Force -ErrorAction 'Stop' } Catch {} } $null = New-Item -Path $outputdir -Name "$OutFilePrefix-$Scope.txt" -ItemType File -ErrorAction Stop } Write-Verbose "${CmdletName}: Adding registry information to '$outfile' for LGPO.exe" # Update file with information Add-Content -Path $Outfile -Value $Scope Add-Content -Path $Outfile -Value $RegistryKeyPath Add-Content -Path $Outfile -Value $RegistryValue If ($Delete) { Add-Content -Path $Outfile -Value 'DELETE' } ElseIf ($DeleteAllValues) { Add-Content -Path $Outfile -Value 'DELETEALLVALUES' } Else { Add-Content -Path $Outfile -Value "$($ValueType):$RegistryData" } Add-Content -Path $Outfile -Value "" } End { } } Function Invoke-LGPO { [CmdletBinding()] Param ( [string]$InputDir = "$TempDir", [string]$SearchTerm ) Begin { [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name } Process { Write-Verbose "${CmdletName}: Gathering Registry text files for LGPO from '$InputDir'" If ($SearchTerm) { $InputFiles = Get-ChildItem -Path $InputDir -Filter "$SearchTerm*.txt" } Else { $InputFiles = Get-ChildItem -Path $InputDir -Filter '*.txt' } ForEach ($RegistryFile in $inputFiles) { $TxtFilePath = $RegistryFile.FullName Write-Verbose "${CmdletName}: Now applying settings from '$txtFilePath' to Local Group Policy via LGPO.exe." $lgporesult = Start-Process -FilePath 'lgpo.exe' -ArgumentList "/t `"$TxtFilePath`"" -Wait -PassThru Write-Verbose "${CmdletName}: LGPO exitcode: '$($lgporesult.exitcode)'" } Write-Verbose "${CmdletName}: Gathering Security Templates files for LGPO from '$InputDir'" $ConfigFile = Get-ChildItem -Path $InputDir -Filter '*.inf' If ($ConfigFile) { $ConfigFile = $ConfigFile.FullName Write-Verbose "${CmdletName}: Now applying security settings from '$ConfigFile' to Local Security Policy via LGPO.exe." $lgporesult = Start-Process -FilePath 'lgpo.exe' -ArgumentList "/s `"$ConfigFile`"" -Wait -PassThru Write-Verbose "${CmdletName}: LGPO exitcode: '$($lgporesult.exitcode)'" } } End { } } #endregion Functions $SecFileContent = @' [Unicode] Unicode=yes [Version] signature="$CHICAGO$" Revision=1 [Registry Values] MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Pku2u\AllowOnlineID=4,1 '@ If (-not (Test-Path $env:SystemRoot\Logs)) { New-Item -Path $env:SystemRoot -Name 'Logs' -ItemType Directory -Force } If (-not (Test-Path $LogDir)) { New-Item -Path "$env:SystemRoot\Logs" -Name 'Configuration' -ItemType Directory -Force } If (-not (Test-Path $TempDir)) { New-Item -Path "$env:Temp" -Name $ScriptName -ItemType Directory -Force } Start-Transcript -Path $Log -Force -IncludeInvocationHeader Write-Output "Checking for lgpo.exe in '$env:SystemRoot\system32'." If (-not(Test-Path -Path "$env:SystemRoot\System32\Lgpo.exe")) { Write-Output "Not found. Downloading Local GPO tool (lgpo.exe) from Internet." $LGPOUrl = Get-InternetUrl -Url $LGPOWebUrl -Searchstring "LGPO" -Verbose If ($LGPOUrl) { $LGPOZip = Get-InternetFile -url $LGPOUrl -OutputDir $TempDir -Verbose If ($LGPOZip) { Write-Output "Expanding '$LGPOZip' to '$TempDir'." Expand-Archive -path "$LGPOZip" -DestinationPath "$TempDir" -force $algpoexe = Get-ChildItem -Path $TempDir -filter 'lgpo.exe' -recurse If ($algpoexe.count -gt 0) { $lgpoexe=$algpoexe[0].FullName Write-Output "Copying '$lgpoexe' to '$env:SystemRoot\system32'." Copy-Item -Path $lgpoexe -Destination "$env:SystemRoot\System32" -force } Else { Write-Error "'lgpo.exe' not found in downloaded zip." Exit 2 } } } } If (Test-Path -Path "$env:SystemRoot\System32\Lgpo.exe") { $SecFileContent | Out-File -FilePath "$tempDir\STIGExceptions.inf" -Encoding unicode $appName = 'STIG_Exceptions' # Remove Setting that breaks Edge Update-LocalGPOTextFile -Scope 'Computer' -RegistryKeyPath 'SOFTWARE\Policies\Microsoft\Edge' -RegistryValue 'ProxySettings' -Delete -outfileprefix $appName -Verbose Invoke-LGPO -Verbose } Else { Write-Error "Unable to configure local policy with lgpo tool because it was not found and could not be downloaded." Stop-Transcript Exit 2 } Remove-Item -Path $TempDir -Recurse -Force -ErrorAction SilentlyContinue Stop-Transcript