Powershell Scripts


#1

I’m trying to test for duplicate IIS App Pool Identities across multiple web sites and app pools on a single server and if a duplicate is found the control fails. The Inspec resource for IIS_apps doesn’t cover this so I’m trying Powershell script instead. As the result of the script is not an error, I don’t see an easy way to use exit_status although that would be my preference.
The alternative is to check stdout. The powershell resource docs suggest that using a simple “write-output” command and then testing for that with “its(‘stdout’)” should work. But that doesn’t seem to be the case.

If I run the script in Powershell on the server it gives me the correct output but if I run the inspec code it passes when it should be failing.

Any hints as to where I’m going wrong would be much appreciated.

script = <<-EOH

    Import-Module webadministration

    $users = Get-Item IIS:\AppPools\* | Get-ItemProperty -name processmodel.username.value

    $dups = $users | select -Unique

    if((Compare-Object -ReferenceObject $users -DifferenceObject $dups) -ne $null) {write-output "NotCompliant"} else {write-output "Compliant"}


EOH

# Controls - 3.2.4
control 'web_server-3.2.4' do                                         # A unique ID for this control
    impact 1.0                                                          # The criticality, if this control fails.
    title 'Compliance Check - IIS AppPool IDs'              # A human-readable title
    desc 'Checks that the AppPool Identity is unique'
  
    describe powershell(script) do
      its('stdout') { should_not match "NotCompliant" }
    end
  end

#2

You could try

describe powershell(script) do
  its('strip') { should ne "NotCompliant" }
end

#3

Hi simark, unfortunately that doesn’t work. I get a Pass whether it’s compliant or not. I tried all the combinations that are described in the documentation without success.


#4

Some additional testing:

script = <<-EOH

    write-output "NotCompliant"

EOH

control 'test_output' do 
    impact 1.0  
    title 'test_output' 
    desc 'test_output'
  
    describe powershell(script) do
      its('stdout') { should_not eq "NotCompliant" }
    end
  end

Changing the write-output command to either Compliant or NotCompliant produces the same result, a pass. Which suggests that stdout is something other than the output of write-output.

using “strip” as suggested by simark, works correctly i.e. if write-output is NotCompliant it will fail, if it’s Compliant it will pass. So the question now is, what is happening in the original powershell script that is different from the test script.


#5

Could you run it in debug mode and send the result when the control gets validated? We could see what gets compared and why is it always passing.


#6

debug doesn’t provide any real insight as far as I can see:
This is the output when using stdout:
[2017-10-09T08:16:44+02:00] DEBUG: Resolve .\exol-iis-compliance\controls\hello.rb into cache C:/Users/Administrator/.in
spec/cache
[2017-10-09T08:16:44+02:00] DEBUG: Dependency does not exist in the cache .\exol-iis-compliance\controls\hello.rb
[2017-10-09T08:16:44+02:00] DEBUG: Starting run with targets: [“Inspec::Profile<tests from .\exol-iis-compliance\controls\hello.rb>”]
[2017-10-09T08:16:44+02:00] DEBUG: Loading ./exol-iis-compliance/controls/hello.rb into #<Inspec::ProfileContext:0x00000
00004dc1578>
[2017-10-09T08:16:44+02:00] DEBUG: Registering rule test_output

Profile: tests from .\exol-iis-compliance\controls\hello.rb
Version: (not specified)
Target: local://

[PASS] test_output: test_output
[PASS] Powershell stdout should not eq “NotCompliant”

Profile Summary: 1 successful control, 0 control failures, 0 controls skipped
Test Summary: 1 successful, 0 failures, 0 skipped

This is the output when using strip:
[2017-10-09T08:17:47+02:00] DEBUG: Resolve .\exol-iis-compliance\controls\hello.rb into cache C:/Users/Administrator/.in
spec/cache
[2017-10-09T08:17:47+02:00] DEBUG: Dependency does not exist in the cache .\exol-iis-compliance\controls\hello.rb
[2017-10-09T08:17:47+02:00] DEBUG: Starting run with targets: [“Inspec::Profile<tests from .\exol-iis-compliance\controls\hello.rb>”]
[2017-10-09T08:17:47+02:00] DEBUG: Loading ./exol-iis-compliance/controls/hello.rb into #<Inspec::ProfileContext:0x00000
00004c0e3c0>
[2017-10-09T08:17:47+02:00] DEBUG: Registering rule test_output

Profile: tests from .\exol-iis-compliance\controls\hello.rb
Version: (not specified)
Target: local://

[CRIT] test_output: test_output (
expected: value != "NotCompliant"
got: “NotCompliant”

 (compared using ==)
 )
 [FAIL]  Powershell strip should not eq "NotCompliant"

 expected: value != "NotCompliant"
      got: "NotCompliant"

 (compared using ==)

Profile Summary: 0 successful controls, 1 control failure, 0 controls skipped
Test Summary: 0 successful, 1 failure, 0 skipped


#7

Going back to the original script:

script = <<-EOH

    $exit_code = 0
    Import-Module webadministration

    $users = Get-Item IIS:\AppPools\* | Get-ItemProperty -name processmodel.username.value

    $dups = $users | select -Unique

    if((Compare-Object -ReferenceObject $users -DifferenceObject $dups) -ne $null) {
        write-host 'NotCompliant' ;throw 
        } else {
            write-host 'Compliant'
        }
        
        

EOH

# Controls - 3.2.4
control 'web_server-3.2.4' do                                         # A unique ID for this control
    impact 1.0                                                          # The criticality, if this control fails.
    title 'Compliance Check - IIS AppPool IDs'              # A human-readable title
    desc 'Checks that the AppPool Identity is unique'
  
    describe powershell(script) do
      its('exit_status') { should eq 0 }
      its('strip') { should_not eq 'NotCompliant' }
    end
  end

In this case the output is “NotCompliant” and throw ensures the exit code is 1. Inspec passes both tests however.
Debug output:

[2017-10-09T08:33:40+02:00] DEBUG: Resolve .\iis-compliance\controls\3.2.4_app_pool_ids.rb into cache C:/Users/Administrator/.inspec/cache
[2017-10-09T08:33:40+02:00] DEBUG: Dependency does not exist in the cache .\iis-compliance\controls\3.2.4_app_pool_ids.rb
[2017-10-09T08:33:40+02:00] DEBUG: Starting run with targets: [“Inspec::Profile<tests from .\iis-compliance\controls\3.2.4_app_pool_ids.rb>”]
[2017-10-09T08:33:40+02:00] DEBUG: Loading ./iis-compliance/controls/3.2.4_app_pool_ids.rb into #Inspec::ProfileContext:0x0000000004d77950
[2017-10-09T08:33:40+02:00] DEBUG: Registering rule web_server-3.2.4

Profile: tests from .\iis-compliance\controls\3.2.4_app_pool_ids.rb
Version: (not specified)
Target: local://

[PASS] web_server-3.2.4: Compliance Check - IIS AppPool IDs
[PASS] Powershell exit_status should eq 0
[PASS] Powershell strip should not eq “NotCompliant”

Profile Summary: 1 successful control, 0 control failures, 0 controls skipped
Test Summary: 2 successful, 0 failures, 0 skipped


#8

So you should use write-output instead of write-host and use the strip approach.
The strip removes whitespace \r\n from stdout