How to get month from month and year value by php - php-7.1

I get this value
$select_month_year = 12/2017
Trying this:
date('m', strtotime($select_month_year))
But output is:
01
But output should be :
12

$select_month_year = "12/2017";
$month = explode('/', $select_month_year)[0];
echo $month;
Or
$date = date_create_from_format('m/Y', '12/2017');
echo $date->format('m');

Related

Active Directory get all user's logon hours(when they're allowed to log in) using powershell

Is it possible to get all the AD user's logon hours and output it into an excel spreadsheet. So something like:
Name
Logon Hours
Bob
9am-6pm
Jane
8am-5pm
Chris
9am-6pm
So far I have Get-AdUser -Filter * -Properties LogonHours | ft Name, LogonHours. However the output is all in binary.
However the output is all in binary.
That happens to be the way AD stores it. The logonHours attribute value consists of 21 bytes, each byte covering an 8-hour window, starting from midnight on Sunday.
As TheMadTechnician notes, converting the byte values to binary/base-2 strings might be the simplest way of accessing each "hour".
With this in mind, we could make a nifty little helper class that can translate the byte array into meaningful logon hour information:
class LogonHourAdapter
{
hidden
[string[]]$_days
LogonHourAdapter([byte[]]$logonHours)
{
if($logonHours.Count -ne 21){
throw [System.ArgumentException]::new('logonHours', "Expected byte array of length 21.")
}
$this._days = [string[]]::new(7)
for($i = 0; $i -lt 7; $i++){
$offset = $i * 3
$this._days[$i] = ($logonHours[$offset..($offset+2)]|ForEach-Object{[convert]::ToString($_,2).PadLeft(8, '0')})-join''
}
}
[bool]
IsAllowedToLogonDuring([DayOfWeek]$day, [int]$hour)
{
if($hour -ge 24){
throw [System.ArgumentOutOfRangeException]::new('hour')
}
return $this._days[$day][$hour] -eq '1'
}
[int[]]
GetLogonHoursOn([DayOfWeek]$day){
$hours = 0..23 |? {$this._days[$day][$_] -eq '1'}
return $hours -as [int[]]
}
}
Now we don't need to worry about parsing the binary data, we just pass the attribute value to an instance of the class:
PS ~> $bob = Get-ADUser Bob -Properties logonHours
PS ~> $bobHours = [LogonHourAdapter]::new($bob.logonHours)
PS ~> $bobHours.IsAllowedToLogonDuring('Monday', 9) # Bob is allowed to logon after 9am
True
PS ~> $bobHours.IsAllowedToLogonDuring('Monday', 6) # But not earlier!
False
Next, we'll want to track "ranges" - contiguous periods throughout each day where the user is allowed to logon.
For each day, simply "walk" through each hour from 0 through 23 and start tracking a new range everytime there's a break:
# Prepare our logon hour adapter
$lha = [LogonHourAdapter]::new($bob.logonHours)
# Extract ranges for each day of the week
$ranges = foreach($day in -split 'Sunday Monday Tuesday Wednesday Thursday Friday Saturday'){
$currRange = $null
0..23|%{
if($lha.IsAllowedToLogonDuring($day, $_)){
if(-not $currRange){
$currRange = [pscustomobject]#{ Day = [DayOfWeek]$day; From = $_; To = $null}
}
$currRange.To = $_ + 1
}else{
if($currRange){
$currRange
$currRange = $null
}
}
}
if($currRange){
$currRange
}
}
Now we just need to group them together so we can express "8-16 (Monday, Tuesday, Friday)" instead of "8-16 (Monday), 8-16 (Tuesday), 8-16 (Wednesday) ... etc.":
$label = $ranges |Group-Object From,To |Sort Count -Descending |ForEach-Object {
'{0:00}-{1:00} ({2})' -f $_.Group[0].From,$_.Group[0].To,(($_.Group.Day |Sort) -join', ')
}
And $label now contains a more human readable version of Bob's logonHours:
PS ~> $label
08-16 (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday)

substitute a variable in a string with another variable

I have a generated string like this:
$x = jhgkjh**May**-**JUN**ojklkjh-jkl
I want to substitute every occurrence in $x of a month abbreviation with the number of the month. So the result will look like this:
$x = jhgkjh**05**-**06**ojklkjh-jkl
For that I created 2 arrays:
$months = "Jan", "Feb", etc...
$Nmonths = "01", "02" , etc...
This loop doesn't work:
$i = 0
do {
$x = $x.replace('$months[$i]','$Nmonths[$i]')
$i = $i+1
}
until ("$i" -eq "12")
$x
Please help !
The sample data looks a little odd with respect to the case of the month strings. Can't really tell if it's case sensitive or not, so here's two slightly different solutions.
Starting whe a hash table of month abbreviations and numbers:
$Months=#{
Jan = '01'
Feb = '02'
Mar = '03'
Apr = '04'
May = '05'
Jun = '06'
Jul = '07'
Aug = '08'
Sep = '09'
Oct = '10'
Nov = '11'
Dec = '12'
}
Using string.replace()
$string = '$x = jhgkjh**May**-**Jun**ojklkjh-jkl'
foreach ($Month in $Months.Keys)
{ $string = $string.Replace($Month,$Months.$Month)}
Using the -Replace operator
$string = '$x = jhgkjh**May**-**JUN**ojklkjh-jkl'
foreach ($Month in $Months.Keys)
{ $string = $string -Replace $Month,$Months.$Month }
The string.replace() method is faster, but the -Replace operator will be more flexible with regard to case sensitivity.
Either way, the foreach loop should be faster than foreach-object
Powershell does not have a do until construct. Try this one liner instead of your loop.
0..11 | % { $x = $x -replace $months[$_],$Nmonths[$_] }
The .. Operator creates a range of integers between the first number and the last.
If you still want to use a traditional flow control structure you can replace the until line with this
while($i -lt 12)

Get/extract the data from log file of last 3 minutes? [duplicate]

This question already has answers here:
Filter log file entries based on date range
(5 answers)
Closed 6 years ago.
I have agent.log file. This file is updating as regular interval.
Entries are as follows 2014-01-07 03:43:35,223 INFO ...some data
I want to extract data of last 3 minutes, Is there any way so that I will get this data using bash script?
Try the solution below:
awk \
-v start="$(date +"%F %R" --date=#$(expr `date +%s` - 180))" \
-v end="$(date "+%F %R")" \
'$0 ~ start, $0 ~ end' \
agent.log
In the start variable there is the time stamp 3 minutes (180 seconds) before the current time.
In the end there is the current time.
$0 ~ start, $0 ~ end selects the lines between start and end
date +"%F %R" gives you the current time down to the minute.
grep '^'"$(date +"%F %R")" agent.log will select the last minute from the file
Now for the previous two minutes it's more tricky... I have developed some scripts that can do complete time manipulation in relative or absolute, and it may be simpler than fiddling with date...
2 minutes ago in the right format: date --date="#$(($(date +"%s") - 2*60))" +"%F %R"
Merge all 3:
NOW=$(date +"%F %R")
M1=$(date --date="#$(($(date +"%s") - 1*60))" +"%F %R")
M2=$(date --date="#$(($(date +"%s") - 2*60))" +"%F %R")
grep '^'"$NOW\|$M1\|$M2" agent.log
my answer considers the followings:
using bash and UNIX/Linux commands
the last log line is the start time not the actual server time
there is no expectation about the lines' date (minutes, days, years, etc.)
the whole script should be expandable to the inverse, or a specified from-to interval
#!/bin/bash
# this script expects descending dates in a log file (reverse as real life examples)!!!
FILE=$1
INTV=180 # sec
while read LINE
do
if [ -z $LAST_LOG_LINE ]
then
# interval stat line
LAST_LOG_LINE=$(date --date="$( echo "$LINE" | sed -e 's/INFO.*//')" +%s)
# mod
#continue
fi
ACT_LOG_LINE=$(date --date="$( echo "$LINE" | sed -e 's/INFO.*//')" +%s)
# print line if not greater than $INTV (180s)
# else break the reading and exit
if [ $(($LAST_LOG_LINE-$ACT_LOG_LINE)) -gt $INTV ]
then
break
fi
# actual print
echo "$LINE"
done < $FILE
Testing:
2014-01-07 03:43:35,223 INFO ...some data
2014-01-07 03:42:35,223 INFO ...some data
2014-01-07 03:41:35,223 INFO ...some data
2014-01-07 03:40:35,223 INFO ...some data
2014-01-07 02:43:35,223 INFO ...some data
2014-01-07 01:43:35,223 INFO ...some data
2014-01-06 03:43:35,223 INFO ...some data
$ /tmp/stack.sh /tmp/log
2014-01-07 03:42:35,223 INFO ...some data
2014-01-07 03:41:35,223 INFO ...some data
2014-01-07 03:40:35,223 INFO ...some data
$
I think you may be somewhat better off using Python in this case. Even if this script doesn't find a date exactly 3 minutes ago, it will still get any log entries in between the time the script was called and 3 minutes ago. This is both concise and more robust than some of the previous solutions offered.
#!/usr/bin/env python
from datetime import datetime, timedelta
with open('agent.log') as f:
for line in f:
logdate = datetime.strptime(line.split(',')[0], '%Y-%m-%d %H:%M:%S')
if logdate >= datetime.now() - timedelta(minutes=3):
print(line)
A Ruby solution (tested on ruby 1.9.3)
You can pass days, hours, minutes or seconds as a parameter and it will search for the expression and on the file specified (or directory, in which case it will append '/*' to the name):
In your case just call the script like so: $0 -m 3 "expression" log_file
Note: Also if you know the location of 'ruby' change the shebang (first line of the script),
for security reasons.
#! /usr/bin/env ruby
require 'date'
require 'pathname'
if ARGV.length != 4
$stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
exit 1
end
begin
total_amount = Integer ARGV[1]
rescue ArgumentError
$stderr.print "error: parameter 'time' must be an Integer\n"
$stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
end
if ARGV[0] == "-m"
gap = Rational(60, 86400)
time_str = "%Y-%m-%d %H:%M"
elsif ARGV[0] == "-s"
gap = Rational(1, 86400)
time_str = "%Y-%m-%d %H:%M:%S"
elsif ARGV[0] == "-h"
gap = Rational(3600, 86400)
time_str = "%Y-%m-%d %H"
elsif ARGV[0] == "-d"
time_str = "%Y-%m-%d"
gap = 1
else
$stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
exit 1
end
pn = Pathname.new(ARGV[3])
if pn.exist?
log = (pn.directory?) ? ARGV[3] + "/*" : ARGV[3]
else
$stderr.print "error: file '" << ARGV[3] << "' does not exist\n"
$stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
end
search_str = ARGV[2]
now = DateTime.now
total_amount.times do
now -= gap
system "cat " << log << " | grep '" << now.strftime(time_str) << ".*" << search_str << "'"
end

How to get all monday (date) for the particular year input

with linux command or perl ,
How to get all monday date for 2010
For example:
20100104 -------- this is jan monday 2010
20100111
20100118
20100125
----
---
---
20101206
20101213
20101220
20101227 -------- this is dec monday 2010
You could use DateTime:
#!/usr/bin/env perl
use strict;
use warnings;
use DateTime;
my $year = 2010;
my $dt = DateTime->new(
'year' => $year,
'month' => 1,
'day' => 1,
);
# find first Monday
while ( $dt->day_name() ne 'Monday' ) {
$dt->add( 'days' => 1 );
}
while ( $dt->year() == $year ) {
print $dt->strftime("%Y%m%d\n");
$dt->add( 'weeks' => 1 );
}
I'd probably do this with DateTime in a very similar manner to Alan's solution. But it's interesting to see how you could also do it using Perl's built-in date-handling facilities.
#!/usr/bin/perl
use strict;
use warnings;
use POSIX 'strftime';
use Time::Local;
my $ONE_DAY = 24 * 60 * 60;
my $ONE_WEEK = 7 * $ONE_DAY;
my $year = shift || 2010;
# Get Jan 1st
my $date = timelocal 0, 0, 0, 1, 0, $year - 1900;
# Get first monday
until (strftime('%a', localtime $date) eq 'Mon') {
$date += $ONE_DAY;
}
while (strftime('%Y', localtime $date) == $year) {
print strftime('%Y%m%d', localtime $date), "\n";
$date += $ONE_WEEK;
}
If you're doing this in Perl, then give Date::Calc a look. I'm a huge fan of Date::Calc, as its large library of functions make these kinds of calculations relatively trivial. For the problem in this question, you could do it with:
use Date::Calc qw(Weeks_in_Year Monday_of_Week);
$wks_in_2010 = Weeks_in_Year(2010);
for ($i = 1; $i <= $wks_in_2010; $i++) {
($mon_year, $mon_month, $mon_day) = Monday_of_Week($i, 2010);
print "$mon_month/$mon_day/$mon_year\n";
}
Remember, Tim Toady.

Linux bash: Multiple variable assignment

Does exist in linux bash something similar to the following code in PHP:
list($var1, $var2, $var3) = function_that_returns_a_three_element_array() ;
i.e. you assign in one sentence a corresponding value to 3 different variables.
Let's say I have the bash function myBashFuntion that writes to stdout the string "qwert asdfg zxcvb".
Is it possible to do something like:
(var1 var2 var3) = ( `myBashFuntion param1 param2` )
The part at the left of the equal sign is not valid syntax of course. I'm just trying to explain what I'm asking for.
What does work, though, is the following:
array = ( `myBashFuntion param1 param2` )
echo ${array[0]} ${array[1]} ${array[2]}
But an indexed array is not as descriptive as plain variable names.
However, I could just do:
var1 = ${array[0]} ; var2 = ${array[1]} ; var3 = ${array[2]}
But those are 3 more statements that I'd prefer to avoid.
I'm just looking for a shortcut syntax. Is it possible?
First thing that comes into my mind:
read -r a b c <<<$(echo 1 2 3) ; echo "$a|$b|$c"
output is, unsurprisingly
1|2|3
I wanted to assign the values to an array. So, extending Michael Krelin's approach, I did:
read a[{1..3}] <<< $(echo 2 4 6); echo "${a[1]}|${a[2]}|${a[3]}"
which yields:
2|4|6
as expected.
I think this might help...
In order to break down user inputted dates (mm/dd/yyyy) in my scripts, I store the day, month, and year into an array, and then put the values into separate variables as follows:
DATE_ARRAY=(`echo $2 | sed -e 's/\// /g'`)
MONTH=(`echo ${DATE_ARRAY[0]}`)
DAY=(`echo ${DATE_ARRAY[1]}`)
YEAR=(`echo ${DATE_ARRAY[2]}`)
Sometimes you have to do something funky. Let's say you want to read from a command (the date example by SDGuero for example) but you want to avoid multiple forks.
read month day year << DATE_COMMAND
$(date "+%m %d %Y")
DATE_COMMAND
echo $month $day $year
You could also pipe into the read command, but then you'd have to use the variables within a subshell:
day=n/a; month=n/a; year=n/a
date "+%d %m %Y" | { read day month year ; echo $day $month $year; }
echo $day $month $year
results in...
13 08 2013
n/a n/a n/a
Chapter 5 of the Bash Cookbook by O'Reilly, discusses (at some length) the reasons for the requirement in a variable assignment that there be no spaces around the '=' sign
MYVAR="something"
The explanation has something to do with distinguishing between the name of a command and a variable (where '=' may be a valid argument).
This all seems a little like justifying after the event, but in any case there is no mention of a method of assigning to a list of variables.
let var1=var2=var3=0
or
var1=var2=var3="Default value"

Resources