Powershell script behaves differently when ran in SQL Server Agent job - powershell

OS: Windows Server 2019 Standard
SQL: Microsoft SQL Server 2017 Standard CU28
PS version: 5.1.17763.2268
I've made a simple script to check if share is accessible before doing restore of databases. If the share is not accessible, it loops until the share becomes accessible.
Script is the first step in SQL Agent job and is set as PowerShell type.
while(!(Test-Path \\192.168.1.92\Share\))
{
Write-EventLog -LogName "Application" -Source "DB_Refresh" -EventID 1001 -EntryType Information -Message "Backup share is not accessible!" -Category 1
sleep 30
}
Write-EventLog -LogName "Application" -Source "DB_Refresh" -EventID 1001 -EntryType Information -Message "Backup share is accessible!" -Category 1
When I ran the script in PS ISE it works as it should. When I ran it in SQL Agent job step, negation works just the opposite as it should. When share is accessible it will loop and when it is not accessible it will not loop.
Any thoughts why does it behave like that? I have tried with -Not instead exclamation mark, but it behaves same.

Related

Is there a way to find which user run what application on a server using Powershell

I am trying to find a way to find out who has ran an application (for example SQL) on a server, just to get some idea.
I tried Get-Process but this doesn't give me historic information, I want to get historical information
Get-Process -IncludeUserName *
what I want the return resule is "name of application", "user who ran it" and the last datetime it was ran by that user'
As for ...
I am trying to find a way to find out who has ran an application (for
example SQL) on a server, just to get some idea.
What you are asking for here is software metering.
SQL is a service that is always running once it is installed, so, no individual user is ever going to be running it. So, that is a bad example. MS Word for example would be a better example.
Yet there is nothing native in PowerShell that does this, software metering, but of course PowerShell can look at event logs. Yet if your auditing is not setup correctly then it's moot. This is better for a software metering tool, and there are several out there. So, why try and reinvent the wheel.
As for ...
I tried Get-Process but this doesn't give me historic information, I
want to get historical information
That is not what a process is nor what Get-Process is for. It, Get-Process only checks for and lists whatever process is currently running, regardless of what/who launched it.
As for...
what I want the return resule is "name of application", "user who ran
it" and the last datetime it was ran by that user'
As long as the process is running, you can get this, with that cmdlet.
However, what are you trying to accomplish by this?
Again, there are purpose built tools to meter software use.
https://learn.microsoft.com/en-us/sccm/apps/deploy-use/monitor-app-usage-with-software-metering
If you must go down this reinvent the wheel road, using scripting, then you need a task watcher on the target machines, which watches for the WinWord process to appear.
Get-Process -IncludeUserName |
Where ProcessName -EQ 'Winword'
... you then write those results to a file or database or your own event log each time you see that process.
Use PowerShell to Create and to Use a New Event Log
New-EventLog -LogName ScriptingGuys -Source scripts
When the command runs, no output appears to the Windows PowerShell console. To ensure the command actually created a new event log, I use
the Get-EventLog cmdlet with the –List parameter. Here is the command
and the associated output.
Write-EventLog -LogName ScriptingGuys -Source scripts -Message “Dude, it works … COOL!” -EventId 0 -EntryType information
Or just to a file
Get-Process -IncludeUserName |
Where ProcessName -EQ 'Winword' |
Select-Object -Property Name, StartTime, Username |
Export-Csv -Path 'F:\Temp\AppLaunchLog.csv' -Append
Import-Csv -Path 'F:\Temp\AppLaunchLog.csv'
# Results
Name StartTime UserName
---- --------- --------
WINWORD 5/23/2019 9:02:53 PM WS01\LabUser001

Forward application log to windows Event log

I want to create a new EventLog for an application running on my server and the log should be taken from the default log file of the application.
Any idea on how to achieve this??.
Do you mean event source?
PowerShell would be
New-EventLog command found here
MSDM New-eventLog
Edit after more detail supplied.
Basic principle of what you want is to query the log file and write the lines found into a event log. This is done like the below:
#Get the content of the error log, gets the top 10 lines ONLY!!
$GetLog = Get-Content -Path D:\Errorlog.txt -totalcount 10
#Now take the data found and write it to the event log under the source and log below
Write-EventLog -LogName "Application" -Source "My Application" -Eventid 1001
-EntryType Error -Message "$Getlog" -Category 1

SCCM Compliance state always 'Compliant' when remediation script runs

We're trying to use SCCM 2012 R2 to run some checks on clients and fix problems when needed. For this we use the PowerShell 'Script' option.
Problem description:
When a 'Discovery script' reports ‘Non-Compliant’ the ‘Remediation script’ is launched. Regardless of the output of the ‘Remediation script’, the result in the report on the client in ‘Configuration Manager > Configurations’ is always ‘Compliant’ even when the ‘Remediation script’ failed to fix the issue and as a result has different output then defined in the ‘Rules for compliance conditions’.
It seems that from the moment a ‘Remediation script’ is selected, the output of the SCCM Compliance State is always ‘Compliant’.
Example:
- Situation:
When there are files or folders in the folder ‘C:\Users\me\Downloads\Input_Test’ the ‘Discovery script’ reports ‘Not compliant to anything’ and kicks of the ‘Remediation script’. The remediation script takes action and can’t fix the problem so it reports back something else then ‘Compliant’, like ‘Non-Compliant’. The SCCM Compliance State should say after execution of the ‘Remediation script’: ‘Non-Compliant’ (which is not the case).
- PowerShell Discovery script:
$Paths = Get-ChildItem -Path 'C:\Users\me\Downloads\Input_Test' | Select -ExpandProperty FullName
New-EventLog -LogName Application -Source SCCMCompliance
if ($Paths) {
$Compliance = 'Non-Compliant'
Write-EventLog -LogName Application -Source SCCMCompliance -EntryType Warning -EventID 1 -Message “Discovery script: Non-Compliant”
}
else {
$Compliance = 'Compliant'
Write-EventLog -LogName Application -Source SCCMCompliance -EntryType Information -EventID 0 -Message “Discovery script: Compliant”
}
$Compliance
- PowerShell Remediation script:
Write-Output 'Non-Compliant'
Write-EventLog -LogName Application -Source SCCMCompliance -EntryType Warning -EventID 1 -Message “Remediation script: Non-Compliant $Paths”
- SCCM Rules for compliance conditions:
- SCCM Compliance State in the Configuration Manager:
In the Windows event viewer all steps can be tracked easily. Am I missing something super obvious here?
After much pain and hurt myself and #DarkLite1 have found that SCCM does not check compliance state after it has performed remediation
From the moment you use a 'Remediation script' the only 2 possible Compliance statusses are: 'Compliant' or 'Exit with error code'. This is done in PowerShell with 'Exit 1'.
For more information please see.
https://social.technet.microsoft.com/Forums/en-US/0f0f3e6f-7e9f-4376-a926-fc0b6aef5bf1/sccm-compliance-state-always-compliant-when-remediation-script-runs?forum=configmanagersecurity

PowerShell: get-eventlog takes too long to complete

I am trying to script the review of the past 30 days of the Application and System Event Logs on remote servers, looking for only Warnings, Errors, or Critical entries.
Borrowing from what I have found here and in other forums, I have come up with:
$Date = Get-Date
$Range = $Date.AddDays(-30)
$Range = $range.ToShortDateString();
$LogName = Read-Host "Which Log? (Application, System)"
$Server = Read-Host "Please Enter Server Name"
get-eventlog $LogName -ComputerName $Server -After $range | where {$_.EntryType -eq "Error" -or $_.EntryType -eq "Warning" -or $_.EntryType -eq "Critical"}
This seems to run fairly quickly, but then hangs several (5-10+) minutes before returning to a prompt, if it does....
Note: if I remove the code:
-After $range
I can simply break the output with ctrl-c and get on with my day, but I'd rather it run as intended and then stop...
So: Any ideas on how to eliminate this hang?
I am also open to ideas on how to make the code more elegant (and faster)!
And I wouldn't mind the script checking both the Application and System logs without having to run twice....
Using the -EntryType string-array parameter on Get-EventLog is much faster than retrieving the entire event log and then filtering with Where-Object
Try get-eventlog -Logname System -EntryType ("Error", "Warning")
However... if I put "Critical" in the -EntryType array, I get: The argument "Critical" does not belong to the set "Error,Information,FailureAudit,SuccessAudit,Warning" specified by the ValidateSet attribute. which makes me wonder whether you should be heeding the advice as listed in Get-Help Get-EventLog:
The cmdlets that contain the EventLog noun (the EventLog cmdlets) work
only on classic event logs. To get events from logs that use the
Windows Event Log technology in Windows Vista and later versions of
Windows, use Get-WinEvent.
Using Get-WinEvent instead, I think this is what you want:
Get-Winevent -FilterHashtable #{LogName="System","Application"; Level=1,2,3; startTime=$range}
That will check for events of level 1, 2, or 3 (Critical, Error, Warning, respectively), and search both the Application and System logs in the same invocation.
I found that for remote systems, I could query several systems at once faster than I could individually, using the same command, if I wrapped it into an Invoke-Command. This is my solution. The more systems, the more time it saved. YMMV
$command = {Get-EventLog -LogName Application -After (Get-Date).AddHours("-24")}
Invoke-Command -ComputerName "foo1","foo2","foo3","foo4" -ScriptBlock $command

Creating a log for a powershell command

I have a simple command to create a CSV file in powershell. Is there a way to log this information separate from the file? I will be needing to manipulate the CSV file, so I don't want to rely on it being my only way of logging the data.
You can also export the output of commands by using the > and >> operators.
example:
You can write all of the Adobe services and their information to a file with this code:
get-service -DisplayName Adobe* > C:\services.txt
if you wanted to append to that with Windows services:
get-service -DisplayName Windows* >> C:\services.txt
so if you wanted to export your CSV to a file you can easily do so by adding a > at the end of the command pointing to the filename you wish to export it to:
> C:\Log_$date.csv
and if you ever needed to append more logs you can simply do so by using the >>
>> C:\Log_$date.csv
if you use > it will overwrite and existing data in the file with new data. >> appends.
If you need a log for people who are in charge of the production you can add your own application log using dedicated Cmdlets. A the moment I create and use one PowerShell log for all my scripts to publish details of the execution (information) and errors (in coordination with good exception handling) for people who are in charge of the production. You can dedicate a log for one script (as it exists a log for DNS etc.)
Here is an example :
# List of logs
Get-EventLog -list
# Creating your own log
New-EventLog -LogName "SlxScripting" -Source "MaSource"
# List of logs
Get-EventLog -list
# Writting in your own log
Write-EventLog -LogName "SlxScripting" -EventId 12 `
-Message "Mon Message"
-Source "MaSource" -EntryType Warning
# Reading in your own log
Get-EventLog -LogName "SlxScripting"
# Suppressing your log
Remove-EventLog -LogName "SlxScripting"