Our monitoring software has custom scripts to download. I downloaded the following PowerShell version of a "Certificates Expiring" script. The software has a command line portion and a script body portion.
The command line
cmd /c powershell.exe -ExecutionPolicy RemoteSigned .\${FileName}.ps1 ${DeviceName} ${UserName} ${Password}
The script body is as such
$certificates= get-childitem cert: -recurse | where-object {$_.NotAfter -gt (get-date)}
Write-Host "Subject Certificate Going to Expire"
Write-Host "Data:";
$certificates | select FriendlyName,#{Name="Expires in (Days)";Expression={($_.NotAfter).subtract([DateTime]::Now).days}} | where "Expires in (Days)" | Sort "Expires in (Days)"
This outputs EVERY certificate on the server when I only want 1 specific certificate. I am somewhat new to PowerShell scripting and I cannot get this particular script to work when using PowerShell locally on the server. When I run it from the monitoring server it outputs fine. I just want to find a parameter I can enter to only look for the one certificate to monitor.
Related
I recently created some PowerShell code that runs perfectly fine on its own or via a command prompt (or a .bat file). Hell, it runs fine as a .cmd file too. When I create a task scheduler task for it to run automatically, the result claims that the job runs 'successfully' but there isn't any output in the folder destination.
The whole goal of the script is to look at a particular subfolder within outlook and find files with a particular name. Then it outputs the latest related attachments to a specific destination.
PowerShell Script
$olFolderInbox = 6
$limit = (Get-Date).AddDays(-1)
$filepath = "C:\Scripts\attachment Project\Spreadsheets"
$ol = New-Object -com outlook.application;
$ns = $ol.GetNamespace("MAPI");
$acct = $ns.GetDefaultFolder($olFolderInbox)
$targetfolder = $acct.Folders | where-object { $_.name -eq "Training" }
$targetfolder.Items | foreach {
if ($_.ReceivedTime -ge $limit) {
$_.attachments |
foreach {
Write-Host "attached file: ",$_.filename
If ($_.filename -match 'SessionCompletions' -or $_.filename -match 'Certifications'){
$_.saveasfile((Join-Path $filepath $_.FileName))
$ol.quit()
}
}
}
}
I've tried all kinds of things to get the Task within Task Scheduler to work and nothing so far seems to help. To start I tried using a basic bat file to run the task. Mind you, this basic format has worked with many other PowerShell related tasks that I set up to run via a bat file.
Basic Bat Script
powershell -file extract-spreadsheets.ps1
Now sometimes I've needed to include an -executionpolicy argument as well but it sadly didn't work in this case.
A little more complex Script
Powershell.exe -executionpolicy RemoteSigned -File "C:\Scripts\attachment Project\extract spreadsheets.ps1"
Note: I made sure the get-executionpolicy on the computer was / is set to RemoteSigned. I've also tried Unrestricted as well.
I've also tried even more complex / different approaches such as . . .
Even more Complex of a Script
#ECHO OFF
SET ThisScriptsDirectory=C:\Scripts\David attachment Project\
SET PowerShellScriptPath=%ThisScriptsDirectory%extract-spreadsheets.ps1
PowerShell -NoProfile -ExecutionPolicy RemoteSigned -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy RemoteSigned -File ""%PowerShellScriptPath%""' -Verb RunAs}";
And I've even tried getting a .cmd file going and trying to use that within Task Scheduler:
##:: This prolog allows a PowerShell script to be embedded in a .CMD file.
##:: Any non-PowerShell content must be preceeded by "##"
##setlocal
##set POWERSHELL_BAT_ARGS=%*
##if defined POWERSHELL_BAT_ARGS set POWERSHELL_BAT_ARGS=%POWERSHELL_BAT_ARGS:"=\"%
##PowerShell -Command Invoke-Expression $('$args=#(^&{$args} %POWERSHELL_BAT_ARGS%);'+[String]::Join(';',$((Get-Content '%~f0') -notmatch '^^##'))) & goto :EOF
$olFolderInbox = 6
$limit = (Get-Date).AddDays(-1)
$filepath = "C:\Scripts\attachment Project\Spreadsheets"
$ol = New-Object -com outlook.application;
$ns = $ol.GetNamespace("MAPI");
$acct = $ns.GetDefaultFolder($olFolderInbox)
$targetfolder = $acct.Folders | where-object { $_.name -eq "Training" }
$targetfolder.Items | foreach {
if ($_.ReceivedTime -ge $limit) {
$_.attachments |
foreach {
Write-Host "attached file: ",$_.filename
If ($_.filename -match 'SessionCompletions' -or $_.filename -match 'Certifications'){
$_.saveasfile((Join-Path $filepath $_.FileName))
$ol.quit()
}
}
}
}
In terms of Task Scheduler, I've tried a multitude of things. To start . . .
For Program / script, I tried various relative and explicit destinations / paths for bat, cmd and PowerShell.
Some examples:
Powershell.exe (again I've also done the full path as well)
C:\Scripts\attachment Project\Training_Reports.bat
Training_Reports.bat
C:\Scripts\attachment Project\extract-spreadsheets.cmd
Note: I've added the above Programs / Actions with and without quotes.
Again, the more frustrating thing is the basic format of Training_Reports.bat with the start in (optional) field of:
C:\Scripts\attachment Project or C:\Scripts\attachment Project\
Has worked with every other script / task I have set up in this format!
I've tried numerous arguments for Execution Policy such as RemoteSigned, Bypass and Unrestricted. I've Added other arguments like: -NoProfile, -noninteractive, -File, -command, -NoLogo etc etc.
Examples of what the Arguments Field has looked like within Task Scheduler:
-ExecutionPolicy Bypass -File "C:\Scripts\attachment Project\extract-spreadsheets.ps1"
-NoLogo -NonInteractive -ExecutionPolicy RemoteSigned -File "C:\Scripts\attachment Project\extract-spreadsheets.ps1"
-NoProfile -ExecutionPolicy Unrestricted -Command "C:\Scripts\attachment Project\extract-spreadsheets.ps1"
I tried using various accounts to 'run the task'.
my domain account (which my account is a global domain admin and has
full permissions)
local Admin account
another Domain Admin Account
I've tried even SYSTEM
None of the accounts above have changed the outcome. Other settings I've looked at that people claim could mess with Tasks.
Turned off 'Start the task only if the computer is on AC power'
Ran the task whether user is logged on or not
Also ran it as when user is logged on
Set it for 'Highest privileges'
I tried running the task in 'configure for' drop down menu for
Windows 10 and Windows 7 / Server 2008.
Other things I have tried:
The initial PowerShell Script had mapped drive destinations. I changed the code to use C drive locations.
Explicitly giving that user account full control over the
directories involved.
Changing ownership of the directories involved to the same user.
Changing the security permissions on the ps1, cmd, bat, outlook.exe files to always Run as Administrator.
Tried running the script with Outlook running and not running.
Note: running it manually works regardless if Outlook is running.
Why is this task within Task Scheduler not outputting correctly?
I use Set-ExecutionPolicy RemoteSigned and download some scripts and modules. These are my scripts so they are not signed. I could use Bypass or RemoteSigned or Unrestricted. I feel that Unrestricted feels a bit over the top so I got with RemoteSigned and indeed, even though my scripts are not signed, I can download them and run them... for a while. Then, "Windows Defender" catches up and completely deletes my scripts. My questions are:
After I download a script, is there a programmatic way with PowerShell to instruct Windows Defender to mark that script on the exclusion list?
Would you say that Unrestricted is a bit unsafe? If so, what is the process of making these scripts signed (or self-signed?), or is this not possible? i.e. Set to Unrestricted so that files are not nuked, then download the file, then somehow put it on an exclusion list, then set the ExecutionPolicy back to RemoteSigned?
Downloaded files are marked as from the internet. Your need to unblock them. Use the built-in cmdlet for that.
# Get specifics for a module, cmdlet, or function
(Get-Command -Name Unblock-File).Parameters
(Get-Command -Name Unblock-File).Parameters.Keys
Get-help -Name Unblock-File -Examples
# Results
<#
Unblock-File -Path C:\Users\User01\Documents\Downloads\PowerShellTips.chm
dir C:\Downloads\*PowerShell* | Unblock-File
Get-Item * -Stream "Zone.Identifier" -ErrorAction SilentlyContinue
C:\ps-test\Start-ActivityTracker.ps1
Get-Item C:\ps-test\Start-ActivityTracker.ps1 | Unblock-File
#>
Get-help -Name Unblock-File -Full
Get-help -Name Unblock-File -Online
Any script you use will be looked at for actions it is performing. Your AV solution (Windows Defender notwithstanding) will take action(s) on it if it appears to be doing unexpected/nefarious things at any point. This has nothing to do with whether they are signed or not, or what ExecutionPolicy you set.
EP = only means allow a script(s) to run, not control what the script does/is going to do and the EP is not a security boundary, as documented in the help files.
Unblock-File Module: Microsoft.PowerShell.Utility
Unblocks files that were downloaded from the Internet.
This is all related to Windows ADS.
'windows alternate data streams downloaded file'
### Detecting Alternate Data Streams with PowerShell and DOS
dir /s /r | find ":DATA"
Get-Item –Path 'C:\users\me\desktop\*' -Stream *
Get-Content –Path 'C:\users\me\some_file.exe' -Stream zone.identifier
# Results
<#
[ZoneTransfer]
ZoneId=3
1
2
#>
Downloaded file via zone 3, we now know that is the Internet Zone as depicted in the chart below.
Value Setting
0 My Computer
1 Local Intranet Zone
2 Trusted sites Zone
3 Internet Zone
4 Restricted Sites Zone
Or using MS SysInternals: streams.exe
I'm hoping you can help. For a bit of background one of our Domain Controllers is Server 2008 R2 and the other is 2012 R2, the 2012 R2 contains the more recent ADMX files. The primary DC is the 2008 version and we plan on upgrading this soon.
I have a Default Domain Policy that contains a basic logon script (.bat) that maps drives and adds documents to users desktops. This policy is Enforced and Link Enabled and pushes to all OU's.
I have an additional Policy setup within an OU that is linked to our domain, this includes a Powershell script that runs at logon. This was created on the secondary DC (2012) as it uses the "Start Screen Layout" feature within Start Menu and Taskbar - the primary DC (2008) doesn't have this features available.
For some reason the Default Domain Policy isn't running, the second policy however is successfully running. Is there any reason this might be happening? I've had a mess with the enforcement options for the second policy but I can't fathom out why it's not running both.
It's definately something to do with the Powershell commands I have running in the second policy, if I remove these the default policy login scripts run fine.
Some More Info
To explain, there's 3 scripts in total (all of which sit in the Policy location within sysvol). The first ps1 file copies a shortcut for devices and printers from a network location that all users have access to and pastes it into %appdata% for all users. Part of this script uses the startlayout.xml to reference this location which then add the shortcut to the users start menu.
Copy-Item -Path "\\Server\Share\*.lnk" -Destination "$env:APPDATA\Microsoft\Windows\Start Menu\Programs"
The next command removes a load of the bloatware that Win 10 installs to a users profile, I won't post all of the apps in the script but a few so you get the gist:
$AppList = #(
"*Microsoft.3dbuilder*"
"*AdobeSystemsIncorporated.AdobePhotoshopExpress*"
"*Microsoft.WindowsAlarms*"
"*Microsoft.Asphalt8Airborne*"
)
foreach ($App in $AppList) {
Get-AppxPackage -Name $App | Remove-AppxPackage -ErrorAction SilentlyContinue
}
The script that is added as the actual logon script references the location the two scripts above sit in and run them:
Get-ChildItem \\domain\SysVol\domain\Policies\'{Policy Number}'\User\Scripts\Logon | ForEach-Object {
& $_.FullName
}
Hope this helps, whether or not there's isn't an exit command maybe I'm not sure as I'm not too savy with Powershell scripting.
Further Update
Hi All, another update. I've made all my drive mappings and document copies through Group Policy now which eliminates the first policy therefore there is only one logon script that should run now which is to remove the Bloatware. I've decided to try and call it from a .bat file using the following command:
PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "\\domainm\SysVol\domain\Policies\{Policy Number}\User\Scripts\Logon\BloatwareRemoval.ps1"'-Wait}"
Again this will only run after a user logs on for the second time. Is there something glaringly obvious I'm missing here?Thanks in advance.
Thanks in advance.
I have a simple PowerShell script that just creates a file. Testing this for a bigger PowerShell script.
Running on Windows Server 2012 R2 - 64-bit
its running under the Administrator account.
Run whether user is logged on or not
Run with highest privileges
Action:
Program/Script
:
Powershell.exe (I've tried it this way and the full path)
Add argumetns: -NoProfile -executionpolicy remotesigned -file C:\Scripts\test.ps1
Get-executionPolicy: RemoteSigned
added "Administrator" to:
Set-PSSSessionConfiguration -Name Microsoft.PowerShell -ShowSecurityDescriptorUI
"Administrator" has "Log on as batch job" permissions
"Administrator" is in the Admins group
PowerShell Script for testing:
$text = "Hello World"
$text | Set-Content TestMyFile.txt
$text | Out-File TestMyFile.txt
$text > TestMyFile.txt
# This is to write into a file or append to the text file created:
$text | Add-Content TestMyFile.txt
$text | Out-File TestMyFile.txt -Append
$text >> TestMyFile.txt
Nothing fancy, just trying to make sure Task Scheduler will execute a PowerShell script.
So What am I missing?
Use full paths in your output code, and for any future problems with running scripts from Task Scheduler, you should first put in logging and try/catch blocks to see what errors/outputs the script is generating before seeking further assistance. Doing this will help you find the answer faster & learn faster at the same time.
Tip: Always only name the program in the 'Program to run' aspect of Task Scheduler, as the Task Scheduler uses its own wrapper to execute the action, and in rare occasions, it can produce undesired results if you place the entire execution line in this field. Always put parameters in the parameters field.
I have a script(Let's call it myPSScript.ps1) which takes two parameters and performs predefined steps. Script is located in a Windows Server box which people login and execute the script. Supports two users to be logged in at the given time.
I want to find out who invoked the script.
(Get-WmiObject -Class Win32_Process | Where-Object {$_.ProcessName -eq 'explorer.exe'}).GetOwner() | Format-Table Domain, User
This works when the user is logged in currently and trying to run the script. But what if I have a batch file in scheduled tasks and run the same script?
In that case the same command returns a null exception, as there is no one logged into the machine.
Is there a way to find out who/which process invoked the powershell script. I vaguely remember Start-Transcript records which user the command is run from etc, so this should be possible?
Thanks!
Sanjeev
Interesting question. I wrote a script with three different ways to get the user like so:
([Environment]::UserDomainName + "\" + [Environment]::UserName) | out-file test.txt
"$env:userdomain\$env:username" | out-file -append test.txt
[Security.Principal.WindowsIdentity]::GetCurrent().Name | out-file -append test.txt
notepad test.txt
Saved it as test.ps1 and called it using runas as:
runas /user:domain\user "powershell e:\test.ps1"
And I got the domain\user all three times in the output. Used runas to just distinguish between the user I am logged in as (me!!) and the domain\user with which I was running it as. So it does give the user that is running the script.