Velvet Star Monitor

Standout celebrity highlights with iconic style.

updates

Create Log File in Powershell

Writer Andrew Henderson

I have the below code and currently it loads all the information on screen. I want it to log to a log file on D:\Apps\Logs.

The log file needs to have the name of the computer it is loading against - so COMPUTERNAME.log

Any idea how I can do this?

Thanks

$computer = gc env:computername
$onetcp = ((get-childitem c:\windows\system32\drivers\tcpip.sys).Versioninfo.ProductMajorPart).tostring() $twotcp = ((get-childitem c:\windows\system32\drivers\tcpip.sys).Versioninfo.ProductMinorPart).tostring() $threetcp = ((get-childitem c:\windows\system32\drivers\tcpip.sys).Versioninfo.ProductBuildPart).tostring() $fourtcp = ((get-childitem c:\windows\system32\drivers\tcpip.sys).Versioninfo.ProductPrivatePart).tostring()
$onedfsr = ((get-childitem c:\windows\system32\dfsrs.exe).Versioninfo.ProductMajorPart).tostring() $twodfsr = ((get-childitem c:\windows\system32\dfsrs.exe).Versioninfo.ProductMinorPart).tostring() $threedfsr = ((get-childitem c:\windows\system32\dfsrs.exe).Versioninfo.ProductBuildPart).tostring() $fourdfsr = ((get-childitem c:\windows\system32\dfsrs.exe).Versioninfo.ProductPrivatePart).tostring()
write-host TCPIP.sys Version on $computer is: "$onetcp.$twotcp.$threetcp.$fourtcp" Write-Host write-host DFSRS.exe Version on $computer is: "$onedfsr.$twodfsr.$threedfsr.$fourdfsr"
Write-Host
If (get-wmiobject win32_share | where-object {$_.Name -eq "REMINST"}) { Write-Host "The REMINST share exists on $computer" } Else { Write-Host "The REMINST share DOES NOT exist on $computer - Please create as per standards" } Write-Host
$hotfix1 = Get-HotFix -Id KB2450944 -ErrorAction SilentlyContinue $hotfix2 = Get-HotFix -Id KB2582284 -ErrorAction SilentlyContinue $hotfix3 = Get-HotFix -Id KB979808 -ErrorAction SilentlyContinue
If ($hotfix1) { Write-Host "Hotfix KB2450944 is installed"
-BackgroundColor Green -ForegroundColor Black } else { Write-Host "Hotfix KB2450944 is NOT installed - Please ensure you install this hotfix" -ForegroundColor "red" }
If ($hotfix2) { Write-Host "Hotfix KB2582284 is installed"
-BackgroundColor Green -ForegroundColor Black } else { Write-Host "Hotfix KB2582284 is NOT installed - Please ensure you install this hotfix" -ForegroundColor "red" }
If ($hotfix3) { Write-Host "Hotfix KB979808 is installed"
-BackgroundColor Green -ForegroundColor Black } else { Write-Host "Hotfix KB979808 is NOT installed - Please ensure you install this hotfix" -ForegroundColor "red" }
1

8 Answers

Put this at the top of your file:

$Logfile = "D:\Apps\Logs\$(gc env:computername).log"
Function LogWrite
{ Param ([string]$logstring) Add-content $Logfile -value $logstring
}

Then replace your Write-host calls with LogWrite.

6

A function that takes these principles a little further.

  1. Add's timestamps - can't have a log without timestamps.
  2. Add's a level (uses INFO by default) meaning you can highlight big issues.
  3. Allows for optional console output. If you don't set a log destination, it simply pumps it out.

    Function Write-Log { [CmdletBinding()] Param( [Parameter(Mandatory=$False)] [ValidateSet("INFO","WARN","ERROR","FATAL","DEBUG")] [String] $Level = "INFO", [Parameter(Mandatory=$True)] [string] $Message, [Parameter(Mandatory=$False)] [string] $logfile ) $Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss") $Line = "$Stamp $Level $Message" If($logfile) { Add-Content $logfile -Value $Line } Else { Write-Output $Line }
    }
2

I believe this is the simplest way of putting all what it is on the screen into a file. It is a native PS CmdLet so you don't have to change or install anything in your script

Start-Transcript -Path Computer.log
Write-Host "everything will end up in Computer.log"
Stop-Transcript
2
function WriteLog
{ Param ([string]$LogString) $LogFile = "C:\$(gc env:computername).log" $DateTime = "[{0:MM/dd/yy} {0:HH:mm:ss}]" -f (Get-Date) $LogMessage = "$Datetime $LogString" Add-content $LogFile -value $LogMessage
}
WriteLog "This is my log message"

Gist with log rotation:

Usage:

. .\logger.ps1
Write-Log "debug message"
Write-Log "info message" "INFO"

Using this Log-Entry framework:

Script:

Function Main { Log -File "D:\Apps\Logs\$Env:computername.log" $tcp = (get-childitem c:\windows\system32\drivers\tcpip.sys).Versioninfo.ProductVersionRaw $dfs = (get-childitem C:\Windows\Microsoft.NET\Framework\v2.0.50727\dfsvc.exe).Versioninfo.ProductVersionRaw Log "TCPIP.sys Version on $computer is:" $tcp Log "DFSVC.exe Version on $computer is:" $dfs If (get-wmiobject win32_share | where-object {$_.Name -eq "REMINST"}) {Log "The REMINST share exists on $computer"} Else {Log "The REMINST share DOES NOT exist on $computer - Please create as per standards"} "KB2450944", "KB3150513", "KB3176935" | ForEach { $hotfix = Get-HotFix -Id $_ -ErrorAction SilentlyContinue If ($hotfix) {Log -Color Green Hotfix $_ is installed} Else {Log -Color Red Hotfix $_ " is NOT installed - Please ensure you install this hotfix"} }
}

Screen output:Screen output

Log File (at D:\Apps\Logs\<computername>.log):

2017-05-31 Write-Log (version: 01.00.02, PowerShell version: 5.1.14393.1198)
19:19:29.00 C:\Users\User\PowerShell\Write-Log\Check.ps1
19:19:29.47 TCPIP.sys Version on is: {Major: 10, Minor: 0, Build: 14393, Revision: 1066, MajorRevision: 0, MinorRevision: 1066}
19:19:29.50 DFSVC.exe Version on is: {Major: 2, Minor: 0, Build: 50727, Revision: 8745, MajorRevision: 0, MinorRevision: 8745}
19:19:29.60 The REMINST share DOES NOT exist on - Please create as per standards
Error at 25,13: Cannot find the requested hotfix on the 'localhost' computer. Verify the input and run the command again.
19:19:33.41 Hotfix KB2450944 is NOT installed - Please ensure you install this hotfix
19:19:37.03 Hotfix KB3150513 is installed
19:19:40.77 Hotfix KB3176935 is installed
19:19:40.77 End

You might just want to use the new TUN.Logging PowerShell module, this can also send a log mail. Just use the Start-Log and/or Start-MailLog cmdlets to start logging and then just use Write-HostLog, Write-WarningLog, Write-VerboseLog, Write-ErrorLog etc. to write to console and log file/mail. Then call Send-Log and/or Stop-Log at the end and voila, you got your logging. Just install it from the PowerShell Gallery via

Install-Module -Name TUN.Logging

Or just follow the link:

Documentation of the module can be found here:

I've been playing with this code for a while now and I have something that works well for me. Log files are numbered with leading '0' but retain their file extension. And I know everyone likes to make functions for everything but I started to remove functions that performed 1 simple task. Why use many word when few do trick? Will likely remove other functions and perhaps create functions out of other blocks. I keep the logger script in a central share and make a local copy if it has changed, or load it from the central location if needed.

First I import the logger:

#Change directory to the script root
cd $PSScriptRoot
#Make a local copy if changed then Import logger
if(test-path "D:\Scripts\logger.ps1"){ if (Test-Path "\\<server>\share\DCS\Scripts\logger.ps1") { if((Get-FileHash "\\<server>\share\DCS\Scripts\logger.ps1").Hash -ne (Get-FileHash "D:\Scripts\logger.ps1").Hash){ rename-Item -path "..\logger.ps1" -newname "logger$(Get-Date -format 'yyyyMMdd-HH.mm.ss').ps1" -force Copy-Item "\\<server>\share\DCS\Scripts\logger.ps1" -destination "..\" -Force } }
}else{ Copy-Item "\\<server>\share\DCS\Scripts\logger.ps1" -destination "..\" -Force
}
. "..\logger.ps1"

Define the log file:

$logfile = (get-location).path + "\Log\" + $QProfile.replace(" ","_") + "-$metricEnv-$ScriptName.log"

What I log depends on debug levels that I created:

if ($Debug -ge 1){ $message = "<$pid>Debug:$Debug`-Adding tag `"MetricClass:temp`" to $host_name`:$metric_name" Write-Log $message $logfile "DEBUG"
}

I would probably consider myself a bit of a "hack" when it comes to coding so this might not be the prettiest but here is my version of logger.ps1:

# all logging settins are here on top
param( [Parameter(Mandatory=$false)] [string]$logFile = "$(gc env:computername).log", [Parameter(Mandatory=$false)] [string]$logLevel = "DEBUG", # ("DEBUG","INFO","WARN","ERROR","FATAL") [Parameter(Mandatory=$false)] [int64]$logSize = 10mb, [Parameter(Mandatory=$false)] [int]$logCount = 25
)
# end of settings
function Write-Log-Line ($line, $logFile) { $logFile | %{ If (Test-Path -Path $_) { Get-Item $_ } Else { New-Item -Path $_ -Force } } | Add-Content -Value $Line -erroraction SilentlyCOntinue
}
function Roll-logFile
{ #function checks to see if file in question is larger than the paramater specified if it is it will roll a log and delete the oldes log if there are more than x logs. param( [string]$fileName = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")+".log", [int64]$maxSize = $logSize, [int]$maxCount = $logCount ) $logRollStatus = $true if(test-path $filename) { $file = Get-ChildItem $filename # Start the log-roll if the file is big enough #Write-Log-Line "$Stamp INFO Log file size is $($file.length), max size $maxSize" $logFile #Write-Host "$Stamp INFO Log file size is $('{0:N0}' -f $file.length), max size $('{0:N0}' -f $maxSize)" if($file.length -ge $maxSize) { Write-Log-Line "$Stamp INFO Log file size $('{0:N0}' -f $file.length) is larger than max size $('{0:N0}' -f $maxSize). Rolling log file!" $logFile #Write-Host "$Stamp INFO Log file size $('{0:N0}' -f $file.length) is larger than max size $('{0:N0}' -f $maxSize). Rolling log file!" $fileDir = $file.Directory $fbase = $file.BaseName $fext = $file.Extension $fn = $file.name #this gets the name of the file we started with function refresh-log-files { Get-ChildItem $filedir | ?{ $_.Extension -match "$fext" -and $_.name -like "$fbase*"} | Sort-Object lastwritetime } function fileByIndex($index) { $fileByIndex = $files | ?{($_.Name).split("-")[-1].trim("$fext") -eq $($index | % tostring 00)} #Write-Log-Line "LOGGER: fileByIndex = $fileByIndex" $logFile $fileByIndex } function getNumberOfFile($theFile) { $NumberOfFile = $theFile.Name.split("-")[-1].trim("$fext") if ($NumberOfFile -match '[a-z]'){ $NumberOfFile = "01" } #Write-Log-Line "LOGGER: GetNumberOfFile = $NumberOfFile" $logFile $NumberOfFile } refresh-log-files | %{ [int32]$num = getNumberOfFile $_ Write-Log-Line "LOGGER: checking log file number $num" $logFile if ([int32]$($num | % tostring 00) -ge $maxCount) { write-host "Deleting files above log max count $maxCount : $_" Write-Log-Line "LOGGER: Deleting files above log max count $maxCount : $_" $logFile Remove-Item $_.fullName } } $files = @(refresh-log-files) # Now there should be at most $maxCount files, and the highest number is one less than count, unless there are badly named files, eg non-numbers for ($i = $files.count; $i -gt 0; $i--) { $newfilename = "$fbase-$($i | % tostring 00)$fext" #$newfilename = getFileNameByNumber ($i | % tostring 00) if($i -gt 1) { $fileToMove = fileByIndex($i-1) } else { $fileToMove = $file } if (Test-Path $fileToMove.PSPath) { # If there are holes in sequence, file by index might not exist. The 'hole' will shift to next number, as files below hole are moved to fill it write-host "moving '$fileToMove' => '$newfilename'" #Write-Log-Line "LOGGER: moving $fileToMove => $newfilename" $logFile # $fileToMove is a System.IO.FileInfo, but $newfilename is a string. Move-Item takes a string, so we need full path Move-Item ($fileToMove.FullName) -Destination $fileDir\$newfilename -Force } } } else { $logRollStatus = $false } } else { $logrollStatus = $false } $LogRollStatus
}
Function Write-Log { [CmdletBinding()] Param( [Parameter(Mandatory=$True)] [string] $Message, [Parameter(Mandatory=$False)] [String] $logFile = "log-$(gc env:computername).log", [Parameter(Mandatory=$False)] [String] $Level = "INFO" ) #Write-Host $logFile $levels = ("DEBUG","INFO","WARN","ERROR","FATAL") $logLevelPos = [array]::IndexOf($levels, $logLevel) $levelPos = [array]::IndexOf($levels, $Level) $Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss:fff") # First roll the log if needed to null to avoid output $Null = @( Roll-logFile -fileName $logFile -filesize $logSize -logcount $logCount ) if ($logLevelPos -lt 0){ Write-Log-Line "$Stamp ERROR Wrong logLevel configuration [$logLevel]" $logFile } if ($levelPos -lt 0){ Write-Log-Line "$Stamp ERROR Wrong log level parameter [$Level]" $logFile } # if level parameter is wrong or configuration is wrong I still want to see the # message in log if ($levelPos -lt $logLevelPos -and $levelPos -ge 0 -and $logLevelPos -ge 0){ return } $Line = "$Stamp $Level $Message" Write-Log-Line $Line $logFile
}

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy