Can't write output from get-service to my log function, can't use select-string

I want to run this in a script to get the status of the service:

$asdf = get-service -displayname ‘Certificate Propagation’

$asdf looks like this:

Status Name DisplayName


Stopped CertPropSvc Certificate Propagation

Below is my script

<#
To run LoggerFunction.ps1
-Place LoggerFunction.ps1 into a directory of your choice that does not have a subdirectory named \LogFiles
-Start Powershell, not PowerShellISE because sometimes it keeps a file open until ISE is closed.
-In Powershell, make that directory your working directory.
-Run the script
-The output file will be found in \LogFiles
#>

$StartTime = get-date
$Year = $StartTime.year
$Month = $StartTime.month
$Day = $StartTime.day

$LogFileDir = join-path -path (get-location) -childpath LogFiles
New-Item -ItemType Directory -Path $LogFileDir -Force | out-null
$LogFileName = $LogFileDir + ‘\Log_’ + $Year + ‘-’ + $Month + ‘-’ + $Day + ‘.log’

Try
{
Function Submit-LogEntry
{
Param(
$message
)

    #Modify the standard u formatted date, for efficiency.  
    #$TimeStamp contains the timestamp written to at the beginninf of each line inside the log file.
    $TimeStamp = get-date -f u
    $TimeStamp = $TimeStamp -replace 'Z',''
    $TimeStamp = $TimeStamp -replace ' ','_'
    
    '{0}  {1}' -f $TimeStamp,$message | Out-File -filepath $LogFileName -Append
        
    } #Function Submit-Log Entry

write-host (' ')
write-host('Please allow the script to run until you see SCRIPT DONE on the screen.')

Submit-LogEntry('First entry written to the log file.')

#Start-Sleep 2
Submit-LogEntry('This entry should be 2 seconds after the first entry.')

#Start-Sleep 3
Submit-LogEntry('This entry should be 3 seconds after the second entry.')

write-host (' ')
write-host ('SCRIPT DONE')


        #Retrieve service status
		$asdf = get-service -displayname 'Certificate Propagation'	
        #(Get-Content $asdf -Raw).Replace("&#8175;r&#8175;n","&#8175;n") | Set-Content $asdf -Force
        
        #If ($asdf -contains 'Stopped' -AND $asdf -contains 'CertPropSvc')
            
            Submit-LogEntry ($asdf)

The last line above sends $asdf to my Submit-LogEntry but the only log written to the log file is “CertPropSvc” or nothing. The other entries above are faithfully written to the log file.


Since that wouldn’t work (and I’ll bet it could be accomplished) I tried to use Select-String to pull the strings from the output, but no success.

select-string -quiet([switch]$Output) -simplematch -pattern ‘Stopped’ -InputObject $asdf

-quiet([switch]$Output) is supposed to get the cmdlet to return true or false, but I am pretty sure I don’t handle the switch correctly.

-InputObject $asdf is to allow me to input a variable as opposed to a file. I want to avoid writing $asdf to the hard drive if I can.

I am not able to parse the contents of $asdf that could then be passed onto the logfile.

OS: Win 7 Pro 64, PowershellISE, ISESteroids
Any help would be greatly appreciated.

In the future, please note the tags (in the bulleted instructions above the posting textbox) used to format code. On longer scripts, it makes a ton of difference in readability.

As a note, PowerShell doesn’t need to use the parentheses in:

Submit-LogEntry ($asdf)

PowerShell functions don’t delimit input in parentheses, and doing so can actually lead to confusion as you move into more complex functions. You’d ideally use:

Submit-LogEntry -message $asdf

The line where you write the log entry:

‘{0} {1}’ -f $TimeStamp,$message | Out-File -filepath $LogFileName -Append

Is the problem. In this case, $message is a copy of $asdf. $asdf is not a string; it is an object, with many properties, as you proved when you just ran $asdf itself. When given an object that’s being treated as a string, PowerShell looks for a Name property and uses that (because most objects have a Name property). So, you’re getting the name. What you saw when you just ran $asdf by itself is the result of PowerShell’s rather powerful formatting system, which operates only on the final output of a pipeline.

If you wanted the description, you’d use $message.description. If you wanted the entire service object, you could use ($message | Out-String), which would engage the formatting system to a degree. If you wanted only a few properties, ($message | select name,status,description | out-string) would produce something. How legible that all ends up being in a log file depends on your personal beliefs about readability :).

Select-String didn’t operate because, again, $asdf isn’t a string. It’s an object. I believe you’re thinking that what the shell displays when you run $asdf is in fact what $asdf contains; that’s a common gotcha in PowerShell. Try this:

$asdf | Get-Member

and

$asdf | Format-List -Prop *

And you’ll see that a ServiceController object (which is what’s in $asdf) is a far more complex beast. PowerShell just parses that down by default. What it’s displaying is not a text string, but rather an ad-hoc construct presented only for human consumption. Out-String performs that same formatting, producing an actual string object from it.

I’ll humbly suggest “Learn PowerShell in a Month of Lunches” as a good way of getting through some of these gotchas without beating your head against too many walls. PowerShell works vastly differently than other shells or programming languages, and some of these things can be hard to figure out on your own, because they’re non-obvious and because PowerShell is doing a crapload under the hood.

Don,

 Thank you for your very thorough, well thought out reply to my message.  It has taught me a lot and there is more to learn as I dig for more info.  You took some real time on this and I appreciate it.

  I could not find "the bulleted instructions above the posting textbox" but I am applying some formatting and hoping it helps.

 I have seen your, though I didn't pay attention to who wrote it, "Learn PowerShell in a Month of Lunches" and will look at it again.

I don’t want you to have to give another long response… Maybe this can be a quick answer. I am going to look at your “Lunches” and assume I can gleen an answer from there.

You can see in my script that I have passed strings and an object into my Function (only string successfully). (Passing strings to a function is so simple when writing to a log file.) Is it best to have a function that will only receive objects, and then I have to pass it only objects? That would require me to convert a string to an object before I pass it to my function.

Having a function that could receive string or object parameters sounds a bit to hairy for me for now.

Thanks again,

BigRedWeather

You actually just wrap your code in the “pre” tags, not the entire post ;).

The difficulty in what you’re asking is that a string IS an object. It’s just a simpler kind of object than, say, a service. It isn’t “better” to pass one or the other; you set up your function so that it can accept whatever is easiest to give it, in terms of the rest of your programming.

If your function is solely going to be writing log messages, then it might be easiest for it to only accept strings:

param( [string]$message )

So that it can object via an error if it’s given something else.

Don,

 Learn Windows PowerShell 3 in a Month of Lunches is very good.  When I get through all of the videos I will have a lot of gotcha's under control.

 I have found some of the chapters on the web and that enables me to copy and paste the scripts into my PS script pane.  Can you tell me where I can find all of the scripts that are in the videos in softcopy form?  I realize this question may cut into your book sales, but I wanted to ask.

BigRedWeather

Honestly I did the videos ad-hoc. I didn’t save the scripts anywhere. Sorry :(.