Showing posts with label PowerShell. Show all posts
Showing posts with label PowerShell. Show all posts

Sunday, October 13, 2019

Powershell: Tail file

You can easily tail a file on Windows using PowerShell.

Get-Content myFileName -Wait

Saturday, February 14, 2015

Powershell to add Read permission on all files in a directory

Recently I needed to update all the files in a specific directory, adding Read permission for the "Users" NTFS group.  Here is a Powershell script to do that.  It can be easily modified to update other users/groups or different permission sets.

$base = "C:\somefolder"
$files = get-childitem $base
foreach ($file in $files) {
    $Acl = Get-Acl $file.FullName
    $Ar = New-Object  system.security.accesscontrol.filesystemaccessrule("Users","Read","Allow")
    $Acl.SetAccessRule($Ar)
    Set-Acl $file.FullName $Acl
}

Wednesday, September 3, 2008

Use PowerShell to capture database schema

Here is a PowerShell script to capture a database schema. Output is written to a directory/datetime file. Multiple databases/servers can be specified via the XML input file.

To run: ./CaptureSchema.ps1 databases.xml

Here is the PowerShell code:

param ([string]$xmlConfig = $(throw '%argument 1 must be XML configuration file path'))

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | out-null
[System.Reflection.Assembly]::LoadWithPartialName("System.Data") | out-null
[System.Reflection.Assembly]::LoadWithPartialName("System.Core") | out-null
[System.Reflection.Assembly]::LoadWithPartialName("System.Linq") | out-null
[System.Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq") | out-null

function ScriptDatabase([string]$serverName, [string]$dbName)
{
$fileName = [String]::Format("{0} {1}.sql", [DateTime]::Now.ToString("yyyyMMdd_HHmmss"), $dbName)
[Console]::Write("Server: $serverName, Database: $dbName, Output: `"$fileName`" . . . ")

$srv = new-object "Microsoft.SqlServer.Management.SMO.Server" $serverName
$db = new-object "Microsoft.SqlServer.Management.SMO.Database"
$scr = New-Object "Microsoft.SqlServer.Management.Smo.Scripter"

$db = $srv.Databases[$dbName]

$scr.Server = $srv
$options = New-Object "Microsoft.SqlServer.Management.SMO.ScriptingOptions"

$options.ClusteredIndexes = $true
$options.Default = $true
$options.DriAll = $true
$options.Indexes = $true
$options.IncludeHeaders = $true
$options.Triggers = $true
$options.AppendToFile = $false
$options.FileName = "$pwd\$fileName"
$options.ToFileOnly = $true

# output all db tables
$scr.Options = $options
$tables = $db.Tables
if ($tables -ne $null)
{
$scr.Script($db.Tables)
}

# output all sprocs
$options.AppendToFile = $true
$sprocs = $db.StoredProcedures | where {$_.IsSystemObject -eq $false}
if ($sprocs -ne $null)
{
$scr.Script($sprocs)
}

# output all db views
$views = $db.Views | where {$_.IsSystemObject -eq $false}
if ($views -ne $null)
{
$scr.Script($views)
}

"done."

}

function SaveSchema($xmlDb)
{
# make folder if not exists yet
$dbName = $xmlDb.Element("Name").Value
$dirName = ".\$dbName"
if ((Test-Path -path $dirName) -eq $False)
{
"Creating directory $dirName..."
ni -type directory $dirName | out-null
}

# save the schema
$serverName = $xmlDb.Element("Server").Value

$prevDir = $pwd
$prevDir
set-location $dirName
ScriptDatabase $serverName $dbName
set-location $prevDir
}

#
# main
#

$xml = [System.Xml.Linq.XElement]::Load((Resolve-Path "$xmlConfig"))

foreach($db in $xml.Elements("Database"))
{
if ($db.Attribute("Enabled").Value -eq $true)
{
SaveSchema $db
}
}

exit

Here is the XML input file:
<Databases>
<Database Enabled="true">
<Name>DatabaseName</Name>
<Server>ServerName</Server>
</Database>
<!-- repeat the Database element if more
than one database schema to capture -->
</Databases>

Saturday, August 9, 2008

PowerShell and CSV files

If you need to process a CSV file, you can use PowerShell's import-csv command. If headers exist in the first line of the CSV, then they will be used as property names on the resulting import-csv output. For example, if you CSV looks like:

Last,First,Middle
Jones,Fred,S
Smith,Sally,M
Johnson,Bob,L

Then you can output the full names like:

import-csv employees.csv |% `
{[string]::format("{0} {1} {2}",$_.first, $_.middle,$_.last)}

Or if you only want last names that start with a "J", you can:

import-csv employees.csv | `
where {$_.last.startswith("J")} |% `
{[string]::format("{0} {1} {2}",$_.first, $_.middle,$_.last)}

Pretty cool, eh?

PowerShell v2 will have the ability to change what the delimiting character is.

Monday, July 28, 2008

PowerShell to encrypt / decrypt app.config sections

Here is a PS script called AppConfigCrypto.ps1 that allows you to encrypt and decrypt sections of an appConfig. Be aware that once a config is encrypted, you can't just copy it from machine to machine since the encryption is done via the default machine key. You should be able to get around this by importing your own keys and modifying the script below. If you don't import a user specified key, then you will have to encrypt on the machine where the application will execute.

Here's the PS script:

param(
[string]$sectionName,
[string]$exePath="app.config",
[switch]$encrypt,
[switch]$decrypt)

function CallExit($msg)
{
$msg
Usage
exit
}

function OKExit($msg)
{
$msg
exit
}

function Usage
{
"Usage: ./AppConfigCrypto.ps1 sectionName exePath [-encrypt | -decrypt]"
}

# check params
if ($sectionName.Trim().Length -eq 0) { CallExit("%You must pass a section name (e.g. appSettings, ConnectionStrings)") }
if ($encrypt -eq $false -and $decrypt -eq $false) { CallExit("%Must specify -encrypt or -decrypt") }
if ($encrypt -ne $false -and $decrypt -ne $false) { CallExit("%Must specify either -encrypt or -decrypt") }

# load the config
$config = [System.Configuration.ConfigurationManager]::OpenExeConfiguration((Resolve-Path $exePath))

# make sure section exists and is readable
$section = $config.GetSection($sectionName)
if ($null -eq $section) { CallExit("%$sectionName section not found") }
if ($section.IsReadOnly()) { CallExit("%$sectionName is read-only") }

if ($encrypt)
{
if ($section.SectionInformation.IsProtected -eq $true) { OKExit("%Section already encrypted") }
"Encrypting $sectionName . . ."
$section.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider")
}
elseif ($decrypt)
{
if ($section.SectionInformation.IsProtected -eq $false) { OKExit("%Section already decrypted") }
"Decrypting $sectionName . . ."
$section.SectionInformation.UnprotectSection()
}

# save section
$section.SectionInformation.ForceSave = $true
$config.Save()

Monday, December 10, 2007

Powershell Cmdlet and Alias listing

Generate a list of PowerShell Cmdlets:

"Name`tSynopsis`tDescription`tFile"
ls -recurse $PSHOME *-Help.xml | foreach {
$fileName = $_.Name
$help = [xml](gc $_.fullName)
$help.helpitems.command | foreach {
write-output ([string]::format("{0}`t{1}`t{2}`t{3}",$_.details.name.trim(),$_.details.description.get_InnerText().trim(),$_.description.get_InnerText().trim().replace("`n", " "),$fileName))
}
}

Generate a list of Aliases:

"Name`tDefinition"
get-alias | sort -property Name | select Name, Definition |% {
write-output ([string]::format("{0}`t{1}", $_.Name,$_.Definition))
}

Each output is tab delimited.

Sunday, December 2, 2007

Counting # of matching lines in file

I wanted to scan a large number XML files and determine which ones had more than 20 elements of a particular type. Here was the PowerShell command-line I used to report on files that contains more than 20 "" elements:

gci *.xml |% {$fn=$_.name; gc $_ | where {$_ -match ""} |% {$count = 0}{++$count}{if ($count -gt 20) {$fn}}}

An easier, but not very good for performance if a large number of files are involved is:

gci f_*.xml | select-string "" | group filename | where {$_.count -gt 20} | select count, name

Tuesday, November 6, 2007

PowerShell to report top 10 results from log file

Ever want to sift through a log file and report on the top 10 occurances of a certain field value? Here is a PowerShell script that will do just that.

I had a log file that contained an IP address in the third field (column index 2 since arrays start at zero in PowerShell). I wanted to know what were the top 10 IPs that were logs. I could call this script like:

./ipcount.ps1 logfile.log 2

When using huge log files, don't forget if you want to redisplay, but not recompute, the results, you can "dot source" the script like:

. ./ipcount.ps1 logfile.log 2

Then $result will always hold the last set of results. Here is the script (3 lines...middle line is really long):

param($file,$index)

$result = gc $file | foreach {$hash=@{}}{$hash[$_.split(',')[[int]$index]] += 1}{$hash.getenumerator()} | sort value -desc | select -first 10

$result

Friday, August 24, 2007

Loading PowerShell scripts at startup

If you want to execute a lot of custom scripts/functions when PowerShell starts up, you can either put them all in your startup profile, or use the method below.

Assuming you have a startup profile named Microsoft.PowerShell_Profile.ps1 in:

%UserProfile%\\My Documents\WindowsPowerShell\Microsoft.PowerShell_profile

Create a subdirectory called something like Includes and place all your custom script files in this directory. Finally add the following code into the startup profile:

foreach ($f in get-childitem $(join-path $(split-path $profile -Parent) "Includes"))
{
. $f.fullname
}


Now, each time PowerShell is started, it will automatically execute all your customer shell scripts/functions.

Powershell Profiles

Extracted from: http://msdn2.microsoft.com/en-us/library/bb613488.aspx

When you add aliases, functions, and variables to Windows PowerShell, you are actually adding them only to the current Windows PowerShell session. If you exit the session or close Windows PowerShell, the changes are lost.

To retain these changes, you can create a Windows PowerShell profile and add the aliases, functions, and variables to the profiles. The profile is loaded every time that Windows PowerShell starts.

To load a profile, your Windows PowerShell execution policy must permit you to load configuration files. If it does not, the attempt to load the profile fails and Windows PowerShell displays an error message.

Understanding the Profiles

You can have four different profiles in Windows PowerShell. The profiles are listed in load order. The most specific profiles have precedence over less specific profiles where they apply.

%windir%\system32\WindowsPowerShell\v1.0\profile.ps1

This profile applies to all users and all shells.

%windir%\system32\WindowsPowerShell\v1.0\ Microsoft.PowerShell_profile.ps1

This profile applies to all users, but only to the Microsoft.PowerShell shell.

%UserProfile%\My Documents\WindowsPowerShell\profile.ps1

This profile applies only to the current user, but affects all shells.

%UserProfile%\\My Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

This profile applies only to the current user and the Microsoft.PowerShell shell.

Creating a Profile

When you create or import variables, aliases, or functions, or add a Windows PowerShell snap-in, these elements are added only to the current console. If you exit the session or close the window, they are gone.

To save the variables, aliases, functions, and commands that you use routinely, and make them available in every Windows PowerShell console, add them to your Windows PowerShell profile.

You can also create, share, and distribute profiles to enforce a consistent view of Windows PowerShell in a larger enterprise.

Windows PowerShell profiles are not created automatically. To create a profile, create a text file with the specified name in the specified location. Typically, you will use the user-specific, shell-specific profile, known as the Windows PowerShell user profile. The location of this profile is stored in the $profile variable.

To display the path to the Windows PowerShell profile, type:

$profile

To determine whether a Windows PowerShell profile has been created on the system, type:

test-path $profile

If the profile exists, the response is True; otherwise, it is False.

To create a Windows PowerShell profile file, type:

new-item -path $profile -itemtype file -force

To open the profile in Notepad, type:

notepad $profile

To create one of the other profiles, such as the profile that applies to all users and all shells, type:

new-item -path C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1 -itemtype file -force

The profile is effective only when the file is located exactly in the path and with the file name that is stored in the $profile variable. Therefore, if you create a profile in Notepad and then save it, or if you copy a profile to your system, be sure to save the file in the path and with the file name specified in the $profile variable.

If you create a profile in Notepad, enclose the file name in quotation marks to preserve the PS1 file name extension. For example:

"Microsoft.PowerShell_profile.ps1"

Without the quotation marks, Notepad appends the .txt file name extension to the file, and Windows PowerShell will not recognize it.

Use the profile to store the aliases, functions, and variables that you use routinely. One very helpful opens your user profile in your favorite text editor. For example, the following command creates a function called pro that opens the user profile in Notepad.

function pro { notepad $profile }

A well-designed profile can make it even easier to use Windows PowerShell and to administer your system.

Monday, August 13, 2007

PowerShell Prompt Utility

This utility allows you to launch a Windows PowerShell command-prompt directly from Windows Explorer via a right-click. Extract, right-click and select "Install".

Download Here

Can't RDP? How to enable / disable virtual machine firewall for Azure VM

Oh no!  I accidentally blocked the RDP port on an Azure virtual machine which resulted in not being able to log into the VM anymore.  I did ...