Any ideea how can I get file from server via sftp by last modify date? (I have this script but I don't know how to implement)
Thank you,
$TodaysDate = Get-Date -UFormat "%d.%m.%Y %R"
function Read-Date {
param(
[String] $prompt
)
$result = $null
do {
$s = Read-Host $prompt
if ( $s ) {
try {
$result = Get-Date $s
break
}
catch [Management.Automation.PSInvalidCastException] {
Write-Host "Date not valid"
}
}
else {
break
}
}
while ( $true )
$result
}
Write-Host "Today's date: $TodaysDate"
$startDate = Read-Date "Enter Start Date"
$endDate = Read-Date "Enter End Date"
Get-SCPFolder -ComputerName $ComputerName -Credential $credentials -RemoteFolder $RemoteLogFolder -LocalFolder $LocalLogFolder -Verbose
Related
Trying to use PowerShell to capture the running status of the "Nessus Essentials" software product. Simply trying to capture product status: running, not running, or other. Getting the below error each time. I've tried changing -like to -match and changing string [warn] [scanner] Not linked to a manager to various other shorter versions, with wildcards and without, to no avail. I still get several lines of an ugly error message when all I want is one line with the string Not linked to a manager returned to console with nothing beneath that.
Pertinent snippet working incorrectly:
} elseif(($agentStatus.stdOut -like "[warn] [scanner] Not linked to a manager")) {
Throw "Not linked to a manager"
The Error:
The Code:
Function Start-ProcessGetStreams {
[CmdLetBinding()]
Param(
[System.IO.FileInfo]$FilePath,
[string[]]$ArgumentList
)
$pInfo = New-Object System.Diagnostics.ProcessStartInfo
$pInfo.FileName = $FilePath
$pInfo.Arguments = $ArgumentList
$pInfo.RedirectStandardError = $true
$pInfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pInfo.CreateNoWindow = $true
$pInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
$proc = New-Object System.Diagnostics.Process
$proc.StartInfo = $pInfo
Write-Verbose "Starting $FilePath"
$proc.Start() | Out-Null
Write-Verbose "Waiting for $($FilePath.BaseName) to complete"
$proc.WaitForExit()
$stdOut = $proc.StandardOutput.ReadToEnd()
$stdErr = $proc.StandardError.ReadToEnd()
$exitCode = $proc.ExitCode
Write-Verbose "Standard Output: $stdOut"
Write-Verbose "Standard Error: $stdErr"
Write-Verbose "Exit Code: $exitCode"
[PSCustomObject]#{
"StdOut" = $stdOut
"Stderr" = $stdErr
"ExitCode" = $exitCode
}
}
Function Get-NessusStatsFromStdOut {
Param(
[string]$stdOut
)
$stats = New-Object System.Collections.Hashtable
$StdOut -split "`r`n" | % {
if($_ -like "*:*") {
$result = $_ -split ":"
$stats.add(($result[0].Trim() -replace "[^A-Za-z0-9]","_").ToLower(),$result[1].Trim())
}
}
Return $stats
}
Function Get-DateFromEpochSeconds {
Param(
[int]$seconds
)
$utcTime = (Get-Date 01.01.1970)+([System.TimeSpan]::fromseconds($seconds))
Return Get-Date $utcTime.ToLocalTime() -Format "yyyy-MM-dd HH:mm:ss"
}
Try {
$nessusExe = Join-Path $env:ProgramFiles -ChildPath "Tenable\Nessus\nessuscli.exe" -ErrorAction Stop
} Catch {
Throw "Cannot find NessusCli.exe"
}
Write-Host "Getting Agent Status..."
$agentStatus = Start-ProcessGetStreams -FilePath $nessusExe -ArgumentList "managed status"
If($agentStatus.stdOut -eq "" -and $agentStatus.StdErr -eq "") {
Throw "No Data Returned from NessusCli"
} elseif($agentStatus.StdOut -eq "" -and $agentStatus.StdErr -ne "") {
Throw "StdErr: $($agentStatus.StdErr)"
} elseif(($agentStatus.stdOut -like "[warn] [scanner] Not linked to a manager")) {
Throw "Not linked to a manager"
} elseif(-not($agentStatus.stdOut -like "*Running: *")) {
Throw "StdOut: $($agentStatus.StdOut)"
} else {
$stats = Get-NessusStatsFromStdOut -stdOut $agentStatus.StdOut
If($stats.last_connection_attempt -as [int]) { $stats.last_connection_attempt = Get-DateFromEpochSeconds $stats.last_connection_attempt }
If($stats.last_connect -as [int]) { $stats.last_connect = Get-DateFromEpochSeconds $stats.last_connect }
If($stats.last_scanned -as [int]) { $stats.last_connect = Get-DateFromEpochSeconds $stats.last_scanned }
}
$stats | Out-Host
Note: Code above is courtesy of here, I've only made a change to the path of Nessus, and I am adding the attempt to capture that it's not connected to a manager.
Modify your code so that it separates standard output from error and so that it handles each line separately.
The following is how to capture standard output (excluding else statements and error handling) of a program (according to your $Proc variable)
if ($proc.Start())
{
while (!$proc.StandardOutput.EndOfStream)
{
$StreamLine = $proc.StandardOutput.ReadLine()
if (![string]::IsNullOrEmpty($StreamLine))
{
# TODO: Duplicate code in this scope as needed or rewrite to use multiline regex
$WantedLine = [regex]::Match($StreamLine, "(?<wanted>.*Not linked to a manager.*)")
$Capture = $WantedLine.Groups["wanted"]
if ($Capture.Success)
{
Write-Output $Capture.Value
}
}
}
}
After that deal with error output separately:
$StandardError = $Proc.StandardError.ReadToEnd()
if (![string]::IsNullOrEmpty($StandardError))
{
# Or use Write-Error
Write-Output $StandardError
}
So I writing some code to run some patching on AWS, I have the following script snippet taken out of the whole thing for now.. I seem to be running into an issue with $PSBoundParameters..
(It's Friday & I've had a long week so I may just need to sleep on it) - but I can't seem to pass anything out of read-host...
param (
[Parameter(Mandatory = $true)][ValidateNotNullorEmpty()][string]$Prof,
[Parameter(Mandatory = $false)][ValidateNotNullorEmpty()][string]$Reminder,
[Parameter(Mandatory = $false)][ValidateNotNullorEmpty()][string]$AddToTGs,
[Parameter(Mandatory = $false)][ValidateNotNullorEmpty()][string]$PatchType,
[Parameter(Mandatory = $false)][ValidateNotNullorEmpty()][string]$Instance,
[Parameter(Mandatory = $false)][ValidateNotNullorEmpty()][string]$Environment
)
function PromptInstance {
$Instance = Read-Host -Prompt "Please Specify the Instance"
Write-Host "Using: $Instance" -ForegroundColor Cyan
}
function PromptEnvtoPatch {
$Environment = Read-Host -Prompt "Please Specify the Environment (e.g. dev)"
Write-Host "Using: $Environment" -ForegroundColor Cyan
}
function PromptReminder {
$title = "Calendar"
$message = "Do you want to Add an Outlook Reminder in 24 Hrs?"
$pA = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Adds an Outlook Reminder"
$pB = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Won''t add a reminder"
$options = [System.Management.Automation.Host.ChoiceDescription[]]($pA, $pB)
$CalResult = $host.ui.PromptForChoice($title, $message, $options, 0)
switch ($CalResult)
{
0 {
$global:CalRes = 1
Write-Host "Reminder will be added.." -ForegroundColor Cyan
}
1 {
$global:CalRes = 0
Write-Host "No Reminder will be added.." -ForegroundColor Cyan
}
}
}
function PromptAddToTGs {
$title = "Re-Add to Target Groups"
$message = "Do you want to have this script Automatically add the instances back into the Target Groups after Patching?"
$pA = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Will ADD the instance back into Target Groups"
$pB = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Will NOT add the instance back into Target Groups"
$options = [System.Management.Automation.Host.ChoiceDescription[]]($pA, $pB)
$result = $host.ui.PromptForChoice($title, $message, $options, 1)
switch ($result)
{
0 {
$global:AddTGRes = 1
Write-Host "Instances WILL be added back into Target Groups" -ForegroundColor Cyan
}
1 {
$global:AddTGRes = 0
Write-Host "Instances will NOT be added back into Target Groups" -ForegroundColor Cyan
}
}
}
function PromptPatchType {
$title = "Patching Type"
$message = "Do you want to Patch a Single Instance, or ALL Instances for a specific Team Env?"
$pA = New-Object System.Management.Automation.Host.ChoiceDescription "&Instance", "Patches an Instance"
$pB = New-Object System.Management.Automation.Host.ChoiceDescription "&ALL Instances for an Env", "Patches ALL Instances in a Team Env"
$pQ = New-Object System.Management.Automation.Host.ChoiceDescription "&Quit", "Cancel/Exit"
$options = [System.Management.Automation.Host.ChoiceDescription[]]($pA, $pB, $pQ)
$PatchResult = $host.ui.PromptForChoice($title, $message, $options, 0)
switch ($PatchResult)
{
0 {
$Instance = Read-Host "Please Specify the Instance Id"
}
1 {
$Environment = Read-Host "Please Specify the Team (i.e. dev)"
}
2 {
Write-Host "You Quitter!... :-)"
Exit
}
}
}
function KickOffPatchingEnv {
param ($Prof, $Reg, $Reminder, $AddToTGs, $PatchType, $Environment)
Write-Host "Using the Following Options: (Profile:$Prof) (Region:$Reg) (Reminder:$Reminder) (AddToTGs:$AddToTGs) (PatchType:$PatchType) (Environment:$Environment)"
}
function KickOffPatchingInst {
param ($Prof, $Reg, $Reminder, $AddToTGs, $PatchType, $Instance)
Write-Host "Using the Following Options: (Profile:$Prof) (Region:$Reg) (Reminder:$Reminder) (AddToTGs:$AddToTGs) (PatchType:$PatchType) (Instance:$Instance)"
}
switch -wildcard ($Prof) {
"*dev*" { $Reg = "eu-west-1"; $Bucket = "s3-dev-bucket" }
"*admin*" { $Reg = "eu-west-1"; $Bucket = "s3-admin-bucket" }
"*prod*" { $Reg = "eu-west-1"; $Bucket = "s3-prod-bucket" }
"*staging*" { $Reg = "eu-west-1"; $Bucket = "s3-staging-bucket" }
}
if (!$PSBoundParameters['Reminder']) { PromptReminder }
if (!$PSBoundParameters['AddToTGs']) { PromptAddToTGs }
if ($PSBoundParameters['PatchType']) {
if (($PatchType -eq "i") -or ($PatchType -eq "instance") -or ($PatchType -eq "I") -or ($PatchType -eq "Instance")) {
if (!$PSBoundParameters['Instance']) { PromptInstance }
KickOffPatchingInst $Prof $Reg $Reminder $AddToTGs $PatchType $Instance
}
if (($PatchType -eq "a") -or ($PatchType -eq "all") -or ($PatchType -eq "A") -or ($PatchType -eq "All")) {
if (!$PSBoundParameters['Environment']) { PromptEnvtoPatch }
KickOffPatchingEnv $Prof $Reg $Reminder $AddToTGs $PatchType $Environment
}
} else { PromptPatchType }
If I use the parameters on the command line, it works fine..
PS C:\Users\myself\Desktop> .\test.ps1 -Prof dev -Reminder y -AddToTGs y -PatchType a -Environment dev
Using the Following Options: (Profile:dev) (Region:eu-west-1) (Reminder:y) (AddToTGs:y) (PatchType:a) (Environment:dev)
But if I omit an option, say for instance the Environment, I'm prompted for it, but the value is not displayed..
PS C:\Users\myself\Desktop> .\test.ps1 -Prof dev -Reminder y -AddToTGs y -PatchType a
Please Specify the Environment (e.g. dev): dev
Using: dev
Using the Following Options: (Profile:dev) (Region:eu-west-1) (Reminder:y) (AddToTGs:y) (PatchType:a) (Environment:)
Environment is empty....
I've tried loads of different things such as setting global:Environment etc, but I always seem to be missing out whichever variable isn't specified in the command?
Maybe this isn't the best way to write this, but i've never used $PSBoundParameters before so this is my first time trying it out..
Can anyone see my glaring error here at all?
TIA :)
#Mathias R. Jessen answered this for me.
I put this in the function
function PromptProfile {
$Prof = Read-Host -Prompt "Please Specify the Profile"
$global:UserProf = $Prof
}
then changed code later on with the global variable, so I can use them
I am new to this Job things. I am getting the error of :
Cannot bind parameter 'ScriptBlock'. Cannot convert the | ".\test7\test7-2.ps1" value of type "System.String" to type "System.Management.Automation.ScriptBlock".
Can anyone tell me and figure out what is happening here?
$importCsv = ".\testData.csv"
$dir = "test\"
$main = ".\test7\test7-2.ps1"
$csv = GetCsv $importCsv
foreach ($i in $csv){
Start-Job -ScriptBlock $main -ArgumentList #($dir,$i.ip,$i.openTime,$i.closeTime)
}
the $main is here:
function Main {
param ($directory, $itemIp, $itemOpen, $itemClose)
$ipAddress = $itemIp
$openTime = $itemOpen
$closeTime = $itemClose
$date = Get-Date -Format "yyyy-MM-dd"
$storeFolder = addFolder $directory $ipAddress
$todayDir = addFolder $storeFolder $date
$pingFile = addFile $todayDir
Write-Host "Date : $date"
Write-Host "Store Folder : $storeFolder"
Write-Host "Today Folder : $todayDir"
Write-Host "File path : $pingFile."
Write-Host "ip address : $ipAddress"
Write-Host "Open Time : $openTime"
Write-Host "Close Time : $closeTime"
$time = Get-Date -Format "HH:mm"
Write-Host "Time : $time"
Compare-Time $time $openTime $closeTime $timeNow $ping4 $ping15 $ipAddress $pingFile 4 3 15 1
}
Then I also tried like this $main = .\test\test7-2.ps1 but it return Cannot bind argument to parameter 'ScriptBlock' because it is| null.
I am writing a script for “My Birthday is *** days away!” countdown and convert it to HTML as MyBirthday.html.
Idid this so far
function Date {
$Name = Read-Host "Please enter your name"
$BirthMonth = Read-Host "Please enter your Month of Birthday"
$BirthDay = Read-Host "Please enter your Day of Birthday"
$BirthYear = (Get-Date).Year
$NumberOfDays=(New-TimeSpan -End "$BirthYear/$BirthMonth/$BirthDay").Days
if ($NumberOfDays -eq 0) {
Write-Host "Happy Birthday $Name. Today is your Birthday! Yeah!"
}
else {
Write-Host "Hello $Name, there are $NumberOfDays days to your Birthday!"
}
}
Out-File Date > C:\Users\Desktop\Date.html
Ideally you want to keep everything as an object (in this case a DateTime object) as it's much easier to manipulate.
I would do it as follows - I've annotated with comments, but if you have any questions ask.
function Date ($Name,$BirthMonth,$BirthDay)
{
#Create a datetime object
$Date = Get-Date -day $BirthDay -month $BirthMonth -year ((Get-Date).Year)
#Check if the entered date is before today
if($Date -lt (Get-Date))
{
#If so add 1 year
$Date = $Date.AddYears(1)
}
$NumberOfDays = New-Timespan -Start (Get-Date) -End $date
if ($NumberOfDays.Days -eq 0)
{
$result = "Happy Birthday $Name. Today is your Birthday! Yeah!"
}
else
{
$result = "Hello $Name, there are $($NumberOfDays.Days) days to your Birthday!"
}
#Create an object to return (Objects are easier and more flexible to work with down the pipeline)
$return = New-Object PSObject -Property #{
'Days Remaining' = $result
}
#Return the object
$return
}
#User input outside of the function (makes the function re-usable)
$Name = Read-Host "Please enter your name"
$BirthMonth = Read-Host "Please enter your Month of Birthday"
$BirthDay = Read-Host "Please enter your Day of Birthday"
#Call the function, pass the input and pipe the output
Date $Name $BirthMonth $BirthDay | ConvertTo-HTML > C:\users\jacob\desktop\date.html
#Demonstration of the returned object
Date $Name $BirthMonth $BirthDay
I am working on an error handling method for my PowerShell scripts. I pass it the error via try/catch on the catch, but I want to iterate through the original params from the command line that called it in order to create an error log and error email.
Here's what I have so far:
# --params--
param(
[string]$Directory,
[string]$ArchiveDirectory,
[string]$ErrorDirectory,
[string]$ErrorEmailFrom,
[string]$ErrorEmailTo,
[string]$ErrorEmailSubject,
[string]$ErrorSMTP,
[string]$FTPSite,
[string]$FTPUser,
[string]$FTPPass,
[string]$FTPRemoteDir
)
# list of arguments for debug
$paramList = $args
# --functions--
function Handle-MyError
{
Write-Host "handle-error"
Write-Host $args[0]; # this is the exception passed in
# -Email alert-
$subject = $ErrorEmailSubject + $FTPSite
# build message
$message = Get-Date -Format "yyyy-mm-dd hh:mm:ss"
$message += "`r`nError: " + $FTPSite + " : " + $args[0]
$message += "`r`nParameters:`r`n"
# Grab each parameter value, using Get-Variable
for ($i=0;$i -lt $paramList.Length; $i++)
{
$message += $paramList[$i]
}
# send email
$smtp = New-Object Net.Mail.SmtpClient($ErrorSMTP)
$smtp.Send($ErrorEmailFrom, $ErrorEmailTo, $subject, $message)
# drop error file
$theDate = Get-Date -Format "yyyymmdd"
$errorFile = $ErrorDirectory + "\" + $theDate + "_ERROR.txt"
Write-Host $errorFile
$message | Out-File $errorFile -Append
}
and in my try/catch:
catch [Exception]
{
Write-Host "SPOT 1"
Handle-MyError $_.
}
At the top, I try to save the original $args as $paramList to loop through later, but it's not working. Inside the Handle-MyError method, $args becomes the error that is passed so I thought if I save the original $argsas $paramList I could access it later, but it's wonky... Ideas?
There are several ways, in order of worst to best:
Use Get-Variable with Scope parameter. Scope number can differ, but it should be at least 2 (Script->Catch->Handle-MyError)
function Handle-MyError
{
Write-Host (Get-Variable -Name ErrorEmailFrom -ValueOnly -Scope 2)
}
Using $Script: prefix
function Handle-MyError
{
Write-Host $Script:ErrorEmailFrom
}
Using $PSBoundParameters
# list of arguments for debug
$paramList = $PsBoundParameters
function Handle-MyError
{
Param
(
$Exception,
$Cfg
)
Write-Host $Cfg.ErrorEmailFrom
}
catch [Exception]
{
Write-host "SPOT 1"
Handle-MyError -Exception $_ -Cfg $paramList
}
Using splatting:
$paramList = $PsBoundParameters
function Handle-MyError
{
Param
(
$Exception,
$ErrorDirectory,
$ErrorEmailFrom,
$ErrorEmailTo,
$ErrorEmailSubject,
$ErrorSMTP
)
Write-Host $ErrorEmailFrom
}
catch [Exception]
{
Write-host "SPOT 1"
Handle-MyError #paramList -Exception $_
}
Here's my final code after some help from #beatcracker.
I combined two pieces of the puzzle.
I need to save the initial params in a local var and Two, ($paramList = $PsBoundParameters)
Access this var/list using .GetEnumerator()
# --params--
param(
[string]$Directory,
[string]$ArchiveDirectory,
[string]$ErrorDirectory,
[string]$ErrorEmailFrom,
[string]$ErrorEmailTo,
[string]$ErrorEmailSubject,
[string]$ErrorSMTP,
[string]$FTPSite,
[string]$FTPUser,
[string]$FTPPass,
[string]$FTPRemoteDir
)
# set params as var for debug later
$paramList = $PsBoundParameters
# --functions--
function Handle-MyError
{
Write-Host "handle-error"
#write-host "Exception:" $args[0]; # this is the exception passed in
# -Email alert-
# build subject
$subject = $ErrorEmailSubject + " " + $FTPSite
# build message
$message = Get-Date -format s
$message += "`r`nError Message: " + $args[0]
$message += "`r`nParameters:`r`n"
$paramList.GetEnumerator() | ForEach-Object `
{
#Write-Host $_.Key "=" $_.Value
if ($_.Key -ne "FTPPass"){
$message += "`r`n" + $_
}
}
}