Tuning PowerShell script for Logs - windows-server-2008-r2

I have written the following script for generating a report regarding SSRS, Excel and performance point by analyzing IIS logs:
Write-Host "`r"
if(!(Test-Path E:\BI_ToolUsage)){New-Item E:\BI_ToolUsage -type directory -force}
$today=(get-date).ToString("dd_MM_yyyy")
Write-Host "Content Farm Selected" -f green
$ConPaths="\\Server_logs\IC1-PS502\IIS-exports\*.log"
"date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) sc-status sc-substatus sc-win32-status time-taken" |Out-file E:\BI_ToolUsage\Content_SSRS_$today.csv
"date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) sc-status sc-substatus sc-win32-status time-taken" |Out-file E:\BI_ToolUsage\Content_ExcelService_$today.csv
"date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) sc-status sc-substatus sc-win32-status time-taken" |Out-file E:\BI_ToolUsage\Content_PerformancePoint_$today.csv
Foreach($path in $ConPaths)
{
$path
gc $path |?{($_ | Select-String "RSViewerPage.aspx" | Out-file E:\BI_ToolUsage\Content_SSRS_$today.csv -Width 30000 -append);($_ | Select-String "xlviewer.aspx" | Out-file E:\BI_ToolUsage\Content_ExcelService_$today.csv -append -Width 30000);($_ | Select-String "PPSWebParts/ppsDashboard.css" |Out-file E:\BI_ToolUsage\Content_PerformancePoint_$today.csv -Width 30000 -append)}
}
$files=Get-ChildItem E:\BI_ToolUsage\Content*
foreach($file in $files){(Get-Content $file.FullName)| Where-Object {$_ -match '\S'}|%{$_ -replace " " , ","}|Out-File $file.FullName}
Write-Host "Completed !"
The thing here is the size of the folder is 19.3 GB and there are 671 files in the location : \Server_logs\IC1-PS502\IIS-exports
When I run this script, it usually takes around 3-4 days for generating the reports. Is it somehow possible to optimize the above script which can reduce the time it takes to complete? As per my knowledge modification in the below piece of code can help a lot:
gc $path |?{($_ | Select-String "RSViewerPage.aspx" | Out-file E:\BI_ToolUsage\Content_SSRS_$today.csv -Width 30000 -append);($_ | Select-String "xlviewer.aspx" | Out-file E:\BI_ToolUsage\Content_ExcelService_$today.csv -append -Width 30000);($_ | Select-String "PPSWebParts/ppsDashboard.css" |Out-file E:\BI_ToolUsage\Content_PerformancePoint_$today.csv -Width 30000 -append)}
Kindly look into this and share your views. Thanks

If you're interested in LogParser, there's any number of sites, but honestly I found the command line help, LogParser.exe -h, and the LogParser.chm file that installs with the program pretty helpful.
Start with something like:
LogParser.exe -i:IISW3C -o:csv "SELECT date, time, s-ip, cs-method, cs-uri-stem,
cs-uri-query, s-port, cs-username, c-ip, cs(User-Agent), sc-status, sc-substatus,
sc-win32-status, time-taken INTO C:\Output\Content_SSRS_2015-08-01.csv
FROM C:\Logs\ex150801.log WHERE cs-uri-query LIKE '%RSViewerPage.aspx%'"`
Note that I may have field names wrong in the query here. You might want to start with SELECT * just to see how it all works. There's also additional fields that LogParser adds (i.e., line number, file name, et al) which you'll see if you run SELECT *. I'm also guessing that the string you're looking for is in cs-uri-query. Without seeing the file it's hard to tell, and it's been just long enough since I've worked with IIS logs to forget.
It's not the most straightforward tool to learn, but the command line help and help file are very good, especially if you're familiar with command line and are somewhat familiar with SQL. If you put a day into learning how it works, it really pays off.
An alternative is the Log Parser Studio program which has a GUI, but I've never really cared for it. I don't like the interface, but I'm very comfortable with command line.

Related

Execute a .exe with arguments from VBA macro in Excel

I want to write a VBA macro to execute the following DOS command (verified, works) by pressing a button in excel:
powershell.exe -command "Get-ADGroupMember -identity "Sec_Tc_RWaccess" -Recursive | Get-ADUser -Property userPrincipalName, Enabled| Select userPrincipalName, Enabled | Export-csv -path C:\temp\textfile.csv"
My idea was to use the function:
Shell (Program,WindowStyle)
but I don't manage to pass the arguments to powershell.exe
Welcome to StackOverflow!
I would run something like this (untested):
Sub test()
Call Shell("powershell -command ""Get-ADGroupMember -identity ""Sec_Tc_RWaccess"" -Recursive | Get-ADUser -Property userPrincipalName, Enabled| Select userPrincipalName, Enabled | Export-csv -path C:\temp\textfile.csv""", vbMaximizedFocus)
End Sub
Please amend your question by including the exact code you are trying to run. That helps us (and other people who have the same problem) a lot.

PowerShell date format not behaving

I'm stumped. :)
My computer has PowerShell 5.1 installed. On another computer (same language) 5.0 it works as expected. (Check using Get-Culture; my locale is nb-NO (Norwegian) )
Consider this:
Get-Date
returns
tirsdag 23. mai 2017 13.13.18
So I do this
Get-Date -Format "H-m-s"
as expected it returns
13-13-18
But then I do this
Get-Date -Format "H:m:s"
You think it returns
13:13:18
right? (it does on PS5.0!) No! I get this:
13.13.18
Only if I do this, is the output what I want:
Get-Date -Format "H\:m\:s"
13:13:18
Can someone please explain why this is? I discovered it "by accident" when I wanted to format a datetime-compatible string for use in SQL Server.
That's because the underlying DateTime formatting function see's : and treats it as a culture-dependent "time separator".
In Norwegian (no-NO), the default time separator is .. You can inspect this with (assuming that no-NO is the current culture):
PS C:\> [CultureInfo]::CurrentCulture.DateTimeFormat.TimeSeparator
.
You can also override this, either by inserting a literal :, with the escape sequence \: as you've already found, or you can override it globally (for the lifetime of the current process/appdomain):
PS C:\> [CultureInfo]::CurrentCulture.DateTimeFormat.TimeSeparator = ":"
PS C:\> Get-Date -Format "H:m:s"
13:13:18

powershell script that reads the last modified date of a folder

I need a script that reads the last modified date of a file and by whom it was modified and outputs to excel. I found a script that changes the modification date.
$a = get-date
$b = Get-ChildItem "C:\Intel" -recurse | ? { !$_.psiscontainer }
foreach ($i in $b)
{
$i.LastWriteTime = $a
}
$b
You can easily get the LastWriteTime by checking the LastWriteTime proprty of a file.
get-childitem * | select FullName,LastWriteTime,Owner
You can check the owner of a file which may or may not be the last person to modify depending on the file type. Some office files will change owner to the last person to write to them but I don't know that this is reliable.
get-childitem * | ForEach-Object {get-acl $_ | select owner}
NTFS doesn't log the last person to modify a file. You can either turn on auditing and check the system audit eventlog or look into the filesystemwatcher class and build a custom script that watches for changes to a folder. (Warning: this may cause performance issues.)

PowerShell Split-Path does not work properly with IIS: drive qualifier

I am using PowerShell v3.0 and the IIS Administration Cmdlets to add and remove websites from my IIS 7 instance. I use Import-Module WebAdministration to make sure the IIS: drive is available, and I am able to use Remove-Item to delete files via the IIS: drive. For some reason though when I use the following code Split-Path always returns an empty string, even though the Remove-Item works fine.
$iisPath = Join-Path "IIS:\Sites" $fullPath
Remove-Item -Path $iisPath
$parent = Split-Path -Path $iisPath -Parent
Even if I comment out the Remove-Item line, Split-Path still returns an empty string. The $iisPath value would look something like this:
IIS:\Sites\Application Services\2.5.12\OurProductServicesDirectory
So I would expect $parent to contain:
IIS:\Sites\Application Services\2.5.12
But $parent is always empty. I have also tried creating the $iisPath using $iisPath = "IIS:\Sites\$fullPath", rather than Join-Path, but still get the same result.
Any ideas why Split-Path doesn't seem to work when using the IIS: drive, or how to fix it?
===UPDATE===
So I created a tiny sample script to see if I could reproduce the problem. Here it is:
$Block = {
Import-Module WebAdministration
$path = "IIS:\Sites\Application Services\2.5.12\OurProductServicesDirectory\"
Test-Path -Path $path
$parent = Split-Path -Path $path -Parent
Write-Host Parent is $parent
}
$Session = New-PSSession -ComputerName "Our.WebServer.local"
Invoke-Command -Session $Session -ScriptBlock $Block
Using this script $parent does get a value, but the text written to the console is:
True
Parent is IIS:Sites\Application Services
when I expect it to be:
True
Parent is IIS:\Sites\Application Services\2.5.12
So in my simple sample script I do get a value back, but it's the wrong value; it returns the grandparent directory instead of the parent directory, and it removes the backslash from after IIS:.
I'm not sure why I get different results in this sample script then in my main script, but both results appear to be wrong. Any suggestions are appreciated.
So because the IIS: qualifier is made valid by importing the WebAdministration module, I'm going to assume that Split-Path was simply never designed to work with the IIS: qualifier, and that is why it doesn't handle it properly.
The work around I found was simply to just exclude IIS:\Sites\ from my path when using Split-Path. So my original example would change to:
Remove-Item -Path "IIS:\Sites\$fullPath"
$parent = Split-Path -Path $fullPath -Parent
So basically I just leave IIS:\Sites\ off of all my paths, and then explicitly add it when needed, such as when calling Remove-Item, Test-Path, Get-ChildItems, etc. It's not the greatest solution, but it works.

Get dbname from multiple web.config files with powershell

I would like to issue a powershell command to return me the connection string (specifically I am looking for the db name value) for all the web sites on a web server...
So I would like to see something like
site1 dbname=Northwind
site2 dbname=Fitch
site3 dbname=DemoDB
I have tried using the IIS Powershell snap-in... I thought I was close with this:
PS C:\Windows\system32> Get-WebApplication | Get-WebConfiguration -filter /connectionStrings/*
but... after looking at the results... my answer doesn't appear to be in there
I am very new to powershell - so excuse my ignornance and inexperience
Any help appreciated!
thanks!
Hopefully, this will get you started. This just assumes there will be a web.config file at the physical path of the web application's physical path. It does not recurse to find other web.config files in the web application. It also assumes your connection strings are in the connectionStrings configuration element.
Import-Module WebAdministration
Get-WebApplication | `
ForEach-Object {
$webConfigFile = [xml](Get-Content "$($_.PhysicalPath)\Web.config")
Write-Host "Web Application: $($_.path)"
foreach($connString in $webConfigFile.configuration.connectionStrings.add)
{
Write-Host "Connection String $($connString.name): $($connString.connectionString)"
$dbRegex = "((Initial\sCatalog)|((Database)))\s*=(?<ic>[a-z\s0-9]+?);"
$found = $connString.connectionString -match $dbRegex
if ($found)
{
Write-Host "Database: $($Matches["ic"])"
}
}
Write-Host " "
}
This post may give you an idea to start with. Basically load in the web.config file as an XML file and then just find the node where the connection string is.
Do something like $myFile = ([xml] Get-Content web.config). You can then pipe that to Get-Member ( $myFile | Get-Member -MemberType Property) to start working your way into the file to see what node has it. I'm not at a computer where I can show you some screenshots to explain it more, but you can check this chapter out from PowerShell.com "Master PowerShell" e-book that explains working with XML very well.

Resources