Closed krjhitch closed 7 years ago
@krjhitch, Thanks for your contribution as a Microsoft full-time employee or intern. You do not need to sign a CLA. Thanks, Microsoft Pull Request Bot
Ran some initial tests and having some issues.
First I ran the following, which created a valid working XML successfully: Start-DscEaScan -ComputerName localhost, dsctest40, junkpc -MofFile 'C:\temp\localhost.mof'
But I got errors when I tried to run Get-DscEaReport -Overall Copy-Item : Could not find a part of the path 'C:\ProgramData\DSCEA\logo.png'
Looking at the Get-DscEaReport function, I see that the error relates to the following code, which when run on its own also throws errors:
if(-not (Test-Path 'C:\ProgramData\DSCEA\logo.png')) {
$env:PSModulePath -split ';' | ForEach-Object {
if(Test-Path (Join-Path $_ 'DSCEA\resources\logo.png')) {
Copy-Item (Join-Path $_ 'DSCEA\resources\logo.png') 'C:\ProgramData\DSCEA\logo.png' -Force
}
}
}
It seems the current code is not checking to make sure there is already a DSCEA folder inside of ProgramData
I was able to get this working with the following edits
if(-not (Test-Path C:\ProgramData\DSCEA)) {
New-Item C:\ProgramData\DSCEA -type directory
}
if(-not (Test-Path 'C:\ProgramData\DSCEA\logo.png')) {
$env:PSModulePath -split ';' | ForEach-Object {
if(Test-Path (Join-Path $_ 'DSCEA\resources\logo.png')) {
Copy-Item (Join-Path $_ 'DSCEA\resources\logo.png') 'C:\ProgramData\DSCEA\' -Force
}
}
}
It also looks like these two versions of the HTML report are writing to the ProgramData directory, when they should be writing to the relative path instead, which is how overall and detailed are correctly behaving:
if($ItemName){
$results | ForEach-Object {
$_.Compliance | ForEach-Object {
$_.ResourcesInDesiredState | ForEach-Object {$_ | Select-Object @{Name="Computer";Expression={$_.PSComputerName}}, ResourceName, InstanceName, InDesiredState}
$_.ResourcesNotInDesiredState | ForEach-Object {$_ | Select-Object @{Name="Computer";Expression={$_.PSComputerName}}, ResourceName, InstanceName, InDesiredState}
}
} | Where-object {$_.InstanceName -ieq $ItemName} |
ConvertTo-HTML -Head $webstyle -body "<img src='C:\ProgramData\DSCEA\logo.png'/><br>","<titlesection>DSC Configuration Report</titlesection><br>","<datesection>Report last run on",$date,"</datesection><p>" |
Out-File $OutPath\ItemComplianceReport-$ItemName.html
Write-Host "Report $OutPath\ItemComplianceReport-$ItemName.html generated"
}
if($ComputerName){
$results | where-object {$_.Computer -ieq $ComputerName} | ForEach-Object {
$_.Compliance | ForEach-Object {
$_.ResourcesNotInDesiredState | Select-Object @{Name="Computer";Expression={$_.PSComputerName}}, ResourceName, InstanceName, InDesiredState
$_.ResourcesInDesiredState | Select-Object @{Name="Computer";Expression={$_.PSComputerName}}, ResourceName, InstanceName, InDesiredState
}
} | ConvertTo-HTML -Head $webstyle -body "<img src='C:\ProgramData\DSCEA\logo.png'/><br>","<titlesection>DSC Configuration Report</titlesection><br>","<datesection>Report last run on",$date,"</datesection><p>" | Out-File $OutPath\ComputerComplianceReport-$ComputerName.html
Write-Host "Report $OutPath\ComputerComplianceReport-$ComputerName.html generated"
}
Good calls on that
Added
if(-not (Test-Path C:\ProgramData\DSCEA)) {
New-Item C:\ProgramData\DSCEA -type directory
}
And made OutPath work correctly
[String]$OutPath = '.'
Out-File (Join-Path -Path $OutPath -ChildPath 'OverallComplianceReport.html')
Get-ItemProperty (Join-Path -Path $OutPath -ChildPath 'OverallComplianceReport.html')
Out-File (Join-Path -Path $OutPath -ChildPath 'DetailedComplianceReport.html')
Get-ItemProperty (Join-Path -Path $OutPath -ChildPath 'DetailedComplianceReport.html')
Out-File (Join-Path -Path $OutPath -ChildPath "ItemComplianceReport-$ItemName.html")
Get-ItemProperty (Join-Path -Path $OutPath -ChildPath "ItemComplianceReport-$ItemName.html")
Out-File (Join-Path -Path $OutPath -ChildPath "ComputerComplianceReport-$ComputerName.html")
Get-ItemProperty (Join-Path -Path $OutPath -ChildPath "ComputerComplianceReport-$ComputerName.html")
I love the PowerShell styling! Woo
Good deal, and I agree I love the styling as well. Was just taking a look at function Convert-DSCEAresultsToCSV and I think we need to add the exceptions file if statement logic to it
I thought the POC for tactical only extended as far as the CSV? For the exceptions we'd need to find the file on the filesystem, show people how it's expected to be formatted, that whole mess
If we still want the exceptions tactically, I wonder if it makes sense to have the user pass them in as a hashtable, sort of like
Get-WinEvent -FilterHashTable @{Log='Application';Date=(Get-Date)}
So I had alreadfy created a solution for the tactical version, here is an example command
Get-DscEaPowerBiReport -ExceptionsFile 'C:\Users\ralph\Documents\DSCEA-exceptions-clean.ps1'
Here is an example of an exceptions file:
$OutPath = "$env:ProgramFiles\DSCEA\Output"
#Remove Global exceptions from results
$DataMinusGlobalExceptions = Import-Csv $OutPath\DAY.CSV |
Where-Object {($_.ResourceName -ne "Registry" -or $_.InstanceName -ne "Numberofpreviouslogonstocache") -and
($_.ResourceName -ne "Service" -or $_.InstanceName -ne "MicrosoftAntimalwareService") #-and
#($_.ResourceName -ne "WindowsFeature" -or $_.InstanceName -ne "XPSViewer")
}
#Remove individual system level exceptions
$DataMinusExceptions = $DataMinusGlobalExceptions |
Where-Object {($_.PSComputerName -ne "dsctest31" -or $_.ResourceName -ne "WindowsFeature" -or $_.InstanceName -ne "Bitlocker") -and
($_.PSComputerName -ne "dsctest31" -or $_.ResourceName -ne "WindowsFeature" -or $_.InstanceName -ne "EnhancedStorage") -and
($_.PSComputerName -ne "dsctest32" -or $_.ResourceName -ne "WindowsFeature" -or $_.InstanceName -ne "DHCPServer")
}
$DataMinusExceptions | Export-Csv -Path $OutPath\DAY.CSV -NoTypeInformation
I don't have the full thought process on it yet, but I feel like we should be able to read in an exceptions hashtable like
@{
ComputersToExempt = @('server1','server2')
ItemsToExempt = @('AntiMalware')
ComputerItemPairsToExempt = @{
'server3' = @('DNSServer')
'server4' = @('DNSServer','NumLogons')
}
}
Then we can use Get-PowerShellDataFile
or whatever it's called, and do a few -notin $Data.ComputersToExempt
type commands
In any case what I'm really wondering is if we can commit dev to master without it, and then raise it on the issues page, or if we should fix it before moving to master (since it'll break functionality)
Gotcha. I'm fine holding it off for now, and for making improvements to it as part of a separate issue.
As far as everything else goes, all looks good except for the write-warning on a scantimeout if the scan fails to complete because a scantimeout is set.
I was able to get my previous Pester integration test working on this latest update, and the only thing it flags is the following:
Start-DscEaScan -ComputerName localhost -MofFile 'C:\temp\localhost.mof' -ScanTimeout 1
When you run this, it does properly timeout, but the warning doesn't work properly right now. Instead of displaying a proper warning, it currently displays the following:
Write-Warning : A positional parameter cannot be found that accepts argument '1'.
At C:\Program Files\WindowsPowerShell\Modules\DSCEA\Functions\Start-DscEaScan.ps1:204 char:13
+ Write-Warning "The DSCEA scan was unable to complete beca ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Write-Warning], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.WriteWarningCommand
This one might require some rigorous testing