Creating a Folder Named After a Date

I like to create folders on the fly for logging  purposes, as well as for keeping track of re-occurring actions, like scanning for disk usage on a given date.

The following PowerShell command is useful for creating a folder with a name in the format YYYYMMDD.

$folderName = “folder1_” + (Get-Date -uFormat  “%Y%m%d”)
This command makes a folder call folder1_20110226.

Another technique is do make the folder, and assign the date to the name all at once.

md (“folder2_” + (Get-Date -uFormat  “%Y%m%d”)).

Below you will see both techniques used, and then the old DIR command just to show that they were created successfully.

Make Folders with Date Names.

Instead of the DIR command I could have used the Powershell commandlette Get-ChildItem folder*, and it would have worked just as well.  I like DIR because I am use to it, and because it is less typing.

That’s all for this entry. Have a nice day.

Thanks,

Patrick

Advertisements

Regular-Expressions

Recently I was asked by my management team to use PowerShell to help with some text searches in a large collection of files, about 15,000 log files generated within our SharePoint system.  The SharePoint team was dealing with an issue and needed to capture email address info related to that issue.  The text they wanted to search for was ‘collabmail’, and then return what was to the left of the @ symbol.

My manager has been working with PowerShell in an attempt to keep his tech skills up to date, so he had already found out how to find the data in the files using the Select-String cmdlet.  Here is what he had so far:

select-string -path *.eml -pattern ‘collabmail’.

Which resulted in the following screenshot of data being returned:

So that was working fine.  I recommend he do two things.

  • Select specific properties from the Select-String cmdlet to make the result more readable.  In this case capturing just the file name and line properties would be useful.
  • Use a ‘Regular Expression’ to filter just the info he needed from the returned line of text from each line.  I will use the term Reg-Exp to describe Regular-Expressions below.

For the Select-String cmdlet here is what I recommended he use:

$allResults = Select-String -Pattern ‘@collabmail’ -Path *.eml | select line, filename

 

Capturing the result from the Select-String cmdlet as the variable $allResults allows us to us a Reg-Exp to filter just the data we want instead of the entire line of text. The above screenshot shows the results from a couple of sample .EML files that I used for testing the  Select-String cmdlet.  Notice the $allResults is an array containing the found text from each file. The two properties of the array are Line and Filename.

Here is where the Reg-Exp comes into the process:

foreach ($result in $allResults){

                [string]$result -match ‘\w+@collabmail’ | Out-Null

We will step through the $allResults array, and for each of its members we will apply the Reg-Exp filter. This will strip off all of the extra data that we don’t need.

Remember my manager only wanted the part of the found email address before the ‘@’ symbol?  So how do we get just the name of the resulting email address?  The following code takes care of that by modifying the returned value from the Reg-Exp:

foreach ($result in $allResults){

                [string]$result -match ‘\w+@collabmail’ | Out-Null

    #We want only the data before the @, so this section will split the result into two parts and keep the first part.

    $emailAddress = $matches[0]

    $emailAddress = $emailAddress.split(‘@’)

 

Here is how the resulting text is sent out into the resulting CSV text file.

$emailAddress = $emailAddress.split(‘@’)

                $fileName = [string]$result.Filename

                $output = $Filename + “`t” + $emailAddress[0]

                Write-Host $output

                Out-File -FilePath .\scanresults.csv -InputObject $output -Append

PowerShell has the ability to capture data as objects to contain data.  The resulting object can be sent to a CSV text file using the Export-CSV cmdlet, but in the case where the size of the resulting data set is unknown I like to output each iteration of a data capture into the output text file.  I’ve had situations where a scan of log files resulted in huge data sets (hundreds of thousands of rows).  The resulting objects I was working with in PowerShell would consume all available memory resources and result in a system crash; nothing permanent just a reboot.  Outputting each line of the data set as it arrives keeps system resource usage to a minimum.

Here is the screenshot from the sample output CSV file:

The full text of the script can be found here: 

EML-Scan.ps1

This script uses a really simple Reg-Exp, but more information can be found on this useful tool quickly using Google.  Here is a good starting point that can be used for Regular-Expressions in general and specifically as they apply to PowerShell:

http://www.regular-expressions.info/powershell.html

Find Users Actively Connected to a Share

The work I do for AT&T deals extensively with performing data migrations; moving user and group data from one server to another.  To make the data transition easier for the active share users I send emails to them indicating when a share is going to move, and what its new location will be?

Q:How do I capture that active user information?

A:  I use a WMI query using the class Win32_ServerConnection.

With Powershell you can easily query a remote server to find out what accounts are connected to all shares, or a specific share.

One of the very nice things about Powershell is that you can create a “one-liner” to grab the information quickliy.  This would be used  as a quick reference.  Here is an example of a one liner to find all of the employees connected to server ServerBravo1

Get-WmiObject Win32_ServerConnection -ComputerName ServerBravo1 select username, sharename, computername | sort sharename | Format-Table -AutoSize

Here is the break down of that command:

Get-WmiObject Win32_ServerConnection: Performs the WMI query using the Get-WMIObject cmdlet.

-ComputerName ServerBravo1: Runs the query on the remote server ServerBravo1.  If the -ComputerName property is excluded then the command is run on the local computer.

selectusername, sharename, computername:  This determines which properties are returned from the query.  I find these to be the most useful properties, but there are a lot more that can be returned.

Here is a list of the properties that could be useful:

Name                           MemberType
—-                                ———-
ActiveTime               Property
Caption                       Property
ComputerName      Property
ConnectionID          Property
Description              Property
InstallDate               Property
Name                          Property
NumberOfFiles       Property
NumberOfUsers     Property
ShareName              Property
Status                         Property
UserName                Property

sort sharename: This sorts the results based on the value of the ShareName property.

Format-Table-AutoSize: This formats the output in columns.  The -autosize option places the columns in a nice compact presentation.  Other output options include format-list, and my personal favorite out-gridview.

The one-liner is nice but you have to type the full text each time.  Since I use this command so much, I prefered to make a function where I can type the function name followed by a server name.  The required typing is a lot less for each use, and you don’t really need to remember the specific property names.

Here is how that funtion would look:

Function to Find Active Share Users on a Server

function get-ShareUsers

{

<#

.SYNOPSIS

Determine which shares are actively being used by employees.

.DESCRIPTION

This provides a live time view of shares currently being accessed by employees. The output can be to the Powershell screen, the out-gridview window, a CSV file, or all of the above.

 

.PARAMETER <paramName>

ServerName – Used to determine the server to scan.

GridView – Enables the output to the gridview.

Export – Enables the output to a CSV file using the export-csv cmdlet.

.EXAMPLE

get-ShareUsers S47715C014001

Description

———–

This command scans a server called S47715C014001 for active share users. The result is sent to the Powershell screen.

.EXAMPLE

get-ShareUsers S47715C014001 -Gridview

Description

———–

This command scans a server called S47715C014001 for active share users. The result is sent to the Powershell screen, and to the out-gridview window.

.EXAMPLE

get-ShareUsers S47715C014001 -Gridview -Export

Description

———–

This command scans a server called S47715C014001 for active share users. The result is sent to the Powershell screen, to the out-gridview window, and to a CSV file called S47715C014001 _Share_Users.csv

#>

[CmdletBinding()]

Param

(

#First parameter

[parameter(Mandatory=$true, #Makes this a required parameter. The user will be prompted for this item if it is not provided.

ValueFromPipeline=$true)] #Allows the server name to be “Piped” into the function.

[String[]] $ServerName, #The name against which to run the query.

#Second parameter – Sends the output to the out-gridview display.

[switch] $Gridview,

#Third parameter – Sends the output to a CSV file for later used.

[switch] $Export

)

 

#Default output to the Powershell interface.

Get-WmiObject Win32_ServerConnection -ComputerName $ServerName | select username, sharename, computername | sort sharename | Format-Table -AutoSize

if ($Gridview -eq $true) #Use this switch if you want to output to the Out-Gridview window.

{

Get-WmiObject Win32_ServerConnection -ComputerName $ServerName | select username, sharename, computername | sort sharename | Out-GridView -Title “$computername Share Users”

}

if ($Export -eq $true) #Use this switch if you want to output to a CSV file.{

[string]$filename = $ServerName+ “_Share_Users.csv”

Get-WmiObject Win32_ServerConnection -ComputerName $ServerName | select username, sharename, computername | sort sharename | Export-Csv -Path $filename -NoTypeInformation

}

}

A few final comments:

  • To make this function available all of the time when you are using PowerShell, paste the function into your PowerShell profile document.  When you do that it will load each time you start PowerShell.
  • Once it is loaded into your PowerShell session, you can find help on this function by typing the following in the PowerShell command line window:

help get-shareusers -Full

This will give examples of how to use the function, and also give detailed information on each of the parameters.

  • Finally, to make it easier to use this function, I have uploaded the text of the script here at my Google page:

Get-ShareUsers.ps1

I hope this is a helpful utility for you.

Please let me know if you have any questions about this, or any of my other posts.

Have a good day.

Patrick

Test Multiple Network Locations with Test-Path

Frequently we relocate a large number of employee home folders in bulk and we need to verify that the move was successful, or we want to test the validity of a large number of network shared folders. This utility does that utilizing the Powershell test-path commandlette.

If you want a basic understanding of how the test-path commandlette works, type this in your Powershell console window:

get-help test-path –full

Here is a general description of what this script utility, Test-Paths.ps1 does:

.SYNOPSIS

This script will test the validity of paths that are contained in the paths.ini file. Output is generated to a CSV file, and to Out-GridView.

.DESCRIPTION

The targets of the test-path command are pulled from the “paths.ini” file that is collocated with the test-paths.ps1 file.

Each target is tested using the Powershell test-path commandlette. Results are stored along with the path name in two output methods.

out-gridview and filename.csv

.PARAMETERS

-nogridview: Prevents the script from generating the Out-GridView window.

-noexport: Prevents the script from generating the exported CSV file.

-outfile filename.csv: Use an alternative name for the output file. CSV extension is best. The default if this switch is not added is testpathresult.csv.

.EXAMPLES

This will give two outputs. A file named testpathresult.csv and the out-gridview window:

.\test-paths.ps1

This example will give no out-gridview window, but will save a CSV file named patrick.csv:

.\test-paths.ps1 -nogridview -outfile patricks.csv

This example will give only the out-gridview window:

.\test-paths.ps1 –noexport

Here are a couple of examples with the script in action. In this first one I will get all failed status results for the test-path commands, but that is because I am using simulated directory paths.

Here are the contents of the paths.ini file which is collocated with the script:

Figure 1: Contents of Paths.ini File

Here are a few screen shots of the utility being run, and some of the selected output screen shots.

.\test-paths.ps1

Figure 2: Command Window Output

You can see that the Powershell command window echoes the target currently being tested.

Since the above example did not use either the of the two exclusion switches, both out-gridview and a CSV file were generated. Here are images of both types of output:

Figure 3: Out-gridview

Figure 4: Testpathresult.CSV File

Notice there are two columns in Figure 3: Accessible and HomeDirPath. In each of these the path tested was shown as False because the path was not found.

Here is another example, but this one excludes the export to the CSV file.

.\test-paths.ps1 –noexport

I added “c:windows” to the paths.ini file to show that the test-path can actually find a valid path. With this one we still see the out-gridview window, but no CSV file is generated. Notice that now we have a True in the Accessible column.

Figure 5: True Path Now Found

And finally, the last example where an alternate output file name is generated using the –outfile parameter:

.\test-paths.ps1 –outfile february28th.csv -nogridview

With this one no out-gridview window is generated, but the output file is unique and will not be overwritten the next time the utility is run.

Figure 6: Alternate Output File Naming

In summary, this utility provides an easy way to test a few, or thousands of network paths very easily.

It is run in a Windows Powershell environment. The target paths are inserted in the paths.ini text file, and the command is run as detailed above.

Let me know if you have any questions about this.

Thanks

Patrick Parkison

Below is the code used in the test-paths.ps1 script.

###################################################################################

<#

.Patrick Parkison

pp1071@att.com

.SYNOPSIS

This script will test the validity of paths that are contained in the paths.ini file. Output is generated to a CSV file, and to Out-GridView.

.DESCRIPTION

The targets of the test-path command are pulled from the “paths.ini” file that is co-located with the test-paths.ps1 file.

Each target is tested using the Powershell test-path commandlette. Results are stored along with the path name in two output methods.

out-gridview and filename.csv

.PARAMETER

-nogridview: Prevents the script from generating the Out-GridView window.

-noexport: Prevents the script from generating the exported CSV file.

-outfile: Use an alternative name for the output file. CSV extension is best. The default if this switch is not added is testpathresult.csv

.EXAMPLES

This will give two outputs. A file named testpathresult.csv and the out-gridview window:

.\test-paths.ps1

This example will give no out-gridview window, but will save a CSV file named patrick.csv:

.\test-paths.ps1 -nogridview -outfile patricks.csv

This example will give only the out-gridview window:

.\test-paths.ps1 -noexport

#>

param([switch] $noGridview, [switch] $noExport, [string]$outfile = “testpathresult.csv”)

#Change the title bar of the script window. This is helpful for long running scripts.

$Host.UI.RawUI.WindowTitle = “Running test-path utility.”

#Makes an array, or a collection to hold all the object of the same fields.

$dataColl = @()

#Get location of the script. Info will be used for getting location of all test targetrs, and for saving output to the same folder.

function Get-ScriptPath

{

Split-Path $myInvocation.ScriptName

}

#ScriptPath will be used to place the output file.

$scriptPath = get-scriptpath

#Paths.ini is a text file containing a list of targets e.g. \servernamesharename

$sourcefile = $scriptPath + “paths.ini”

<#

This is the output CSV file. It is overwritten each time the script is run.

If a historical record is desired, a date can be appended to the file name. See this reference on how to do that: https://thescriptlad.com/?s=date

#>

$outputfile = $scriptPath + “” + $outfile

foreach ($path in (gc $sourcefile)){

$dataObject = New-Object PSObject

Write-Host “Scanning: $path”

Add-Member -inputObject $dataObject -memberType NoteProperty -name “Accessible” -value (Test-Path $path )

Add-Member -inputObject $dataObject -memberType NoteProperty -name “HomeDirPath” -value $path

$dataColl += $dataObject

}

#This section is used to generate the out-gridview display.

if (!$noGridview)

{

$label = “Test-Path Results. Total Responses: ” + $dataColl.count

$dataColl | Out-GridView -Title $label

}

#Output to the CSV file for use in Excel.

if (!$noExport)

{

$dataColl | Export-Csv -noTypeInformation -path $outputfile

}

#Restore the default command window title bar.

$Host.UI.RawUI.WindowTitle = $(get-location)

Text To Voice Conversion

Here is a little script that is fun to use, and could be useful in some applications.

I put this in my profile, so that I am greeted with the data whenever I start a Powershell session.

$today = [DateTime]::Now # Get Current time and date.
$Voice = new-object -com SAPI.SpVoice #Make a voice object using the com object.
$Voice.Speak( “Good Day Patrick!”, 1 )#1 causes function to continue w/o wating.
$day = $today.DayOfWeek #Determine the day.
$dayNumber = $today.Day #Determine the day number
$Voice.Speak( “Today is $day the $dayNumber”, 1 )

The only down side to this is the fact that there is no suffix on the $dayNumber value. A good way to work around that would be to create a switch statement.

Here is an example of how that could be implemented.

switch ($dayNumber)
{
19 {$properDay = “nineteenth” }
20 {$properDay = “twentieth” }
}

To implement this for the entire month, you would add the entire range of possible day numbers from 1 to 31.
Here is how the whole script would look.

$today = [DateTime]::Now # Get Current time and date.
$Voice = new-object -com SAPI.SpVoice #Make a voice object using the com object.
$Voice.Speak( “Good Day Patrick!”, 1 ) #The 1 parameter after the text causes the function to continue without wating.
$day = $today.DayOfWeek #Determine the day.$dayNumber = $today.Day #Determine the day number

switch ($dayNumber)

{
1 {$properDay = “first” }
2 {$properDay = “second” }
3 {$properDay = “third” }
4 {$properDay = “fourth” }
5 {$properDay = “fifth” }
6 {$properDay = “sixth” }
7 {$properDay = “seventh” }
8 {$properDay = “eigth” }
9 {$properDay = “ninth” }
10 {$properDay = “tenth” }
11 {$properDay = “eleventh” }
12 {$properDay = “tweflth” }
13 {$properDay = “thirteenth” }
14 {$properDay = “four-teenth” }
15 {$properDay = “fifteenth” }
16 {$properDay = “sixteenth” }
17 {$properDay = “seventeenth” }
18 {$properDay = “eighteenth” }
19 {$properDay = “nineteenth” }
20 {$properDay = “twentieth” }
21 {$properDay = “twenty-first” }
22 {$properDay = “twenty-second” }
23 {$properDay = “twenty-third” }
24 {$properDay = “twenty-fourth” }
25 {$properDay = “twenty-fifth” }
26 {$properDay = “twenty-sixth” }
27 {$properDay = “twenty-seventh” }
28 {$properDay = “twenty-eight” }
29 {$properDay = “twenty-ninth” }
30 {$properDay = “thirtieth” }
31 {$properDay = “thirty-first” }

}
$Voice.Speak( “Today is $day the $properDay”, 1 )

The voice utilized by this com object reminds me of the voice from the movie
“War Games”. The classic line is “Would you like to play a game?”