Showing posts with label New-Object. Show all posts
Showing posts with label New-Object. Show all posts

Friday, April 10, 2015

Everyday Powershell - Part 32 - Create-TaskbarPinnedShortcut

So you may have a need to pin things to taskbars... We Certainly do apparently clicking on the start menu is a step too far for some users... Long and boring story.

Anyway here's some powershell.

$itemstopin = "C:\Program Files (x86)\Microsoft Office\Office15\excel.exe",
"C:\Program Files (x86)\Microsoft Office\Office15\outlook.exe",
"C:\Program Files (x86)\Microsoft Office\Office15\winword.exe"

foreach($item in $itemstopin){
    $path = [system.io.path]::getdirectoryname($item)
    $app = [system.io.path]::getfilename($item)
    $shell = new-object -com "Shell.Application"
    $folder = $shell.Namespace($path) 
    $item = $folder.Parsename($app)
    $item.InvokeVerb('taskbarpin')
}
All credit goes to this post on stackoverflow http://stackoverflow.com/questions/9739772/how-to-pin-to-taskbar-using-powershell I look at that site and often wonder how many programmers there really are versus how many cut and paste from there.

SOMEONE is writing all this code that the rest of us are copying. Wonder what the ratio really is?

Friday, September 5, 2014

Everyday Powershell - Part 27 - Uploading files to a FTP server

Full credit to Goyuix for his awesome example on StackOverflow which I am shamlessly ripping off for this Post!

$logpath = "C:\SomePath"
$ftpserver = "ftp://someFTP.com//"
$user = "User"
$password = "Password"
$ftppath = "Somefolder"
$todayslogs = Get-ChildItem $logpath | where {$_.CreationTime -gt ((get-date).AddDays(-1))}

foreach($log in $todayslogs){
    $uploadpath = $ftpserver + $ftppath + "/" + $log.Name 
    # create the FtpWebRequest and configure it
    $ftp = [System.Net.FtpWebRequest]::Create($uploadpath)
    $ftp = [System.Net.FtpWebRequest]$ftp
    $ftp.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
    $ftp.Credentials = new-object System.Net.NetworkCredential($user,$password)
    $ftp.UseBinary = $true
    $ftp.UsePassive = $true
    # read in the file to upload as a byte array
    $content = [System.IO.File]::ReadAllBytes($log.FullName)
    $ftp.ContentLength = $content.Length
    # get the request stream, and write the bytes into it
    $rs = $ftp.GetRequestStream()
    $rs.Write($content, 0, $content.Length)
    # be sure to clean up after ourselves
    $rs.Close()
    $rs.Dispose()
}

This one was written to automate the upload of some logs. It happens every day so that's why we just (get-date).addays(-1) but that where on get-childitem can be anything you like.

One thing to note is the hardcoded password. You may not want to do this, depends on your security requirements. You can save the credentials in another file as a secure.string if you like. There's probably a post coming about that.

Wednesday, December 11, 2013

Everyday Powershell - Part 12 - Change the owner of all files in a folder

This is the next part in an ongoing series about Powershell. You may have heard about how awesome Powershell is but have struggled to find ways to make it useful in your day to day work. That's what this series is going to address. It'll provide scripts and knowledge to address practical everyday problems

This one was another request. We love requests please send more!

The reader wanted a script that would recursively set  the owner of all files in a folder.

As usual the scripting guys are all over this kind of thing.
http://blogs.technet.com/b/heyscriptingguy/archive/2008/04/15/how-can-i-use-windows-powershell-to-determine-the-owner-of-a-file.aspx

Our contribution was putting it in a loop and adding a progress indicator. Vital sanity proofing if you are going to watch this thing as it runs over thousands of files...
$path = c:\test
$objUser = New-Object System.Security.Principal.NTAccount("SOMEDOMAIN", "SOMEUSER")

$list = get-childitem $path -recurse
$count = $list.count
$i = 0

foreach ($file in $list)
{
    $i++
    $prog = ($i/$count) * 100
    Write-Progress -Activity "Processing" -percentcomplete $prog -Status $file.fullname
    $objFile = Get-Acl $file.fullname
    $objFile.SetOwner($objUser)
    Set-Acl -aclobject $objFile -path $file.fullname
}

Working with Access Control Lists is a bit funny. We can't just add things to the ACL we've got make a copy of it;
$objFile = Get-Acl $file.fullname

Perform the modification;
$objFile.SetOwner($objUser)

and then apply it to the file as a new ACL.
Set-Acl -aclobject $objFile -path $file.fullname 

Wednesday, November 20, 2013

Everyday Powershell - Part 9 - Scheduling Powershell in Powershell

This is the next part in an ongoing series about Powershell. You may have heard about how awesome Powershell is but have struggled to find ways to make it useful in your day to day work. That's what this series is going to address. It'll provide scripts and knowledge to address practical everyday problems

Todd Klindt brings us this awesome bit of trickery. You may remember from Part 1 of this series we went over how to schedule a script using the GUI... But what kind of scripter uses the GUI for anything!? Well Todd's post over on the weekend scripter gives us everything we need to ditch the GUI for scheduling tasks.

So this script can be used to schedule any other scripts. We've used the one from Part 2 saved it in C:\powershell with the filename say-bofhexcuse.ps1

#http://blogs.technet.com/b/heyscriptingguy/archive/2013/11/09/weekend-scripter-use-powershell-to-back-up-sharepoint-installation.aspx?utm_source=twitterfeed&utm_medium=twitter
$password = ConvertTo-SecureString 'Wouldn'tyouliketoknow?' -AsPlainText -Force
$account = New-Object system.management.automation.pscredential 'SomeUser', $password
$opt = New-ScheduledJobOption -RunElevated
Register-ScheduledJob -Name BOFH-SPEAKS -FilePath C:\Powershell\say-BOFHexcuse.ps1 -Credential $account -ScheduledJobOption $opt

$t = New-JobTrigger -atlogon

Get-ScheduledJob -Name BOFH-SPEAKS | Set-ScheduledJob -Trigger $t

Once we've got the job setup we can test it with;
Start-Job -DefinitionName BOFH-SPEAKS

The New-JobTrigger bit will accept all kinds of triggers, you'll need to check the doco for all the tricky parts. We're just running this one at logon. So when you login of a morning you'll get a new excuse!

Wednesday, November 13, 2013

Everyday Powershell - Part 8 - Powershell Slideshow

This is the next part in an ongoing series about Powershell. You may have heard about how awesome Powershell is but have struggled to find ways to make it useful in your day to day work. That's what this series is going to address. It'll provide scripts and knowledge to address practical everyday problems

First let me congratulate you finding this article! Especially if you came via Google. Finding a blog post on "Powershell Slideshows" among all the "Powerpoint" slideshows would have been an interesting challenge!

Let's say you wanted a PC to boot up and show a slideshow of images in a given folder. Do you think that you'd need some third party software? Could windows photo viewer do it? A colleague of mine was about to create a video in Windows Movie Maker before I asked...

"Why don't we try POWERSHELL?"

$folder = "C:\Users\someuser\Documents\Pictures\"
$wait = 1

[void][reflection.assembly]::LoadWithPartialName("System.Windows.Forms")
$form = new-object Windows.Forms.Form
$form.Text = "Image Viewer"
$form.WindowState= "Maximized"
$form.controlbox = $false
$form.formborderstyle = "0"
$form.BackColor = [System.Drawing.Color]::black

$pictureBox = new-object Windows.Forms.PictureBox
$pictureBox.dock = "fill"
$pictureBox.sizemode = 4
$form.controls.add($pictureBox)
$form.Add_Shown( { $form.Activate()} )
$form.Show()

do
{
    $files = (get-childitem $folder | where { ! $_.PSIsContainer})
    foreach ($file in $files)
    {
        $pictureBox.Image = [System.Drawing.Image]::Fromfile($file.fullname)
        Start-Sleep -Seconds $wait
        $form.bringtofront()
    }
}
While ($running -ne 1)

Most of this was pinched from here;

Our contribution is the fact it's Fullscreen and the Do While loop. Those clever observers among us will notice the $running will never equal 1 so that do loop is infinite. Which suits our purpose just fine.

What started as a way to settle an argument with a colleague (about the usefulness of powershell in media rich environments) became a great way to demo the windows.forms objects!

Beware though it is a bit of mess from a UI perspective. You can't quit the form once it's shown, you can alt tab and kill it from task manager when you need to close it. It suits what we need because it's just for a PC that boots up and runs a slide show, then shuts down at night. The users won't have to ever touch this PC. This is not something I'd give to end users to interact with. But it's fine for our purposes.

Wednesday, November 6, 2013

Everyday Powershell - Part 7 - Powershell to Upgrade Powershell 4

This is the next part in an ongoing series about Powershell. You may have heard about how awesome Powershell is but have struggled to find ways to make it useful in your day to day work. That's what this series is going to address. It'll provide scripts and knowledge to address practical everyday problems!

This is a script you can run that'll upgrade you to the newest version of the Windows Management Framework (version 4). What's so good about WMF4? Why Powershell 4 is in it!

#http://download.microsoft.com/download/3/D/6/3D61D262-8549-4769-A660-230B67E15B25/Windows8-RT-KB2799888-x64.msu

if ($PSVersionTable.psversion.Major -ge 4)
{
    write-host "Powershell 4 Installed already you don't need this"
    Exit-PSSession
}

$powershellpath = "C:\powershell"

function download-file
{
    param ([string]$path, [string]$local)
    $client = new-object system.net.WebClient
    $client.Headers.Add("user-agent", "PowerShell")
    $client.downloadfile($path, $local)
}


if (!(test-path $powershellpath))
{
    New-Item -ItemType directory -Path $powershellpath
}

if (($PSVersionTable.CLRVersion.Major) -lt 4)
{
    $DownloadUrl = "http://download.microsoft.com/download/B/A/4/BA4A7E71-2906-4B2D-A0E1-80CF16844F5F/dotNetFx45_Full_setup.exe"
    $FileName = $DownLoadUrl.Split('/')[-1]
    download-file $downloadurl "$powershellpath\$filename"
    ."$powershellpath\$filename"
}

#You may need to reboot after the .NET 4.5 install if so just run the script again.

if ([System.IntPtr]::Size -eq 4)
{
    $DownloadUrl = "http://download.microsoft.com/download/3/D/6/3D61D262-8549-4769-A660-230B67E15B25/Windows6.1-KB2819745-x86-MultiPkg.msu"
}
Else
{
    $DownloadUrl = "http://download.microsoft.com/download/3/D/6/3D61D262-8549-4769-A660-230B67E15B25/Windows6.1-KB2819745-x64-MultiPkg.msu"
}

$FileName = $DownLoadUrl.Split('/')[-1]
download-file $downloadurl "$powershellpath\$filename"

."$powershellpath\$filename"

You can use this script to save you typing ".net 4.5 framework" and "windows management framework 4" into Google. It's got the Microsoft download URLs hardcoded, and we use our tricky download-file function from weeks ago. Which is the great thing about getting into scripting, you really only have to solve a particular problem once! When the solution is in your script repository you can clone your own work!

The bulk of this script is just checking what .net and powershell versions are installed continuing or breaking depending on that. This should be familiar territory if you've been following along for the past 6 weeks.

We do check the Environment and check if we're running a 64bit version of windows then download the correct WMF file for your OS. That's a bit tricky.

We've also included the WMF for windows 8 so if you've got it installed you can copy and paste that into the $downloadurl (while you wear a potplant for a hat you mad windows 8 bugger you).


Wednesday, October 30, 2013

Everyday Powershell - Part 6 - Replacing Printers

This is the next part in an ongoing series about Powershell. You may have heard about how awesome Powershell is but have struggled to find ways to make it useful in your day to day work. That's what this series is going to address. It'll provide scripts and knowledge to address practical everyday problems!

When the print server migrations happen they can be a big pain. Our last migration was breeze for us and the users thanks to Powershell!

This script requires a little more leg work than usual in that you've got to setup a file that can be referred to to map the old print queues to the new ones. Once you've got that though, you're a loop and a few WMI queries away from promised land of automagic printer migration!

The tricky part here is running the script as the user logs on... There are many ways to do this, and there's probably a good post on the subject coming.

$replacements = import-csv "\\SOMENETWORKSHARE\printers.csv"
$printers = Get-WmiObject -class win32_printer # obviously you can tart up this query with a bit of filtering e.g. | where {$_.name -like "*Toshiba*" -and $_.systemname -eq "\\OLD PRINT SERVER" -and $_.name -notlike "*SOMESITE*"}
$default = Get-WmiObject -class win32_printer -Filter "default = $true"

foreach ($printer in $printers)
{
    $printername = ""
    $newprinter = ""
    $newprinterpath = ""
    if ($printer.systemname -ne "\\NewPrintServer")
    {
        $printername = $printer.name
        $newprinter = $replacements | where {$_.old -like "*$printername*"} | select -expandproperty new
        $newprinterpath = '\\NewPrintServer\'+$newprinter
        write-host "Replacing... $printername with $newprinterpath"
        (new-Object -com WScript.Network).AddWindowsPrinterConnection($newprinterpath) | out-null
        $printer.delete()
    }
}

$printername = $default.sharename
$defaultprinter = $replacements | where {$_.old -like "*$printername*"} | select -expandproperty new
(get-wmiobject -class win32_printer | where {$_.sharename -like "$defaultprinter"}).setdefaultprinter() 


This worked really well for our users. The tricky part was mapping the default printer to the new queue. I just ended up running it through the same logic as I'd setup for the replacements.

This is also another good example of a foreach loop in action.

The CSV needs two colums "old" and "new" this should contain the sharenames of the printers you are migrating... Like this;

old,new
old-hp,new-hp
old-samsung,new-samsung

Post a comment if you need any clarification on how to use this.

Wednesday, October 16, 2013

Everyday Powershell - Part 4 - Chore List

This is the next part in an ongoing series about Powershell. You may have heard about how awesome Powershell is but have struggled to find ways to make it useful in your day to day work. That's what this series is going to address. It'll provide scripts and knowledge to address practical everyday problems!

I found this in my travels a while back;
http://www.reddit.com/r/PowerShell/comments/1n8w5w/assigning_daily_family_chores/

It's not my script but I have made a couple of changes for the sake of compatibility. I've picked it out because it's a fantastic idea and a great opportunity to look at two important functions in powershell. import-csv and foreach.

Have a look at the script;

# requires -version 2
# Chores.ps1
# Parses chores.csv, randomly assigns the chores and sends an email to each person
# Retrieves family members from family.csv. First person listed in family.csv receives full summary email

$today = (get-date).DayOfWeek
$chores = import-csv chores.csv | where-object {$_.$today -eq 1} | select Chore, Weight
$chores = $chores | get-random
-count ($chores.count) | sort-object -property Weight -Descending
$family = import-csv family.csv
$choremsg = @()
$smtpuser = "person@gmail.com"
$smtppassword = "notapassword"

write-host Generating chores list for $Today

# Create first column in $chorelist array to hold the names of who is doing the chore
foreach ($familymember in $family)
{
    $choremsg = $choremsg + ("`r`n" + $familymember.person + "'s Chores for the day:`r`n-------------------------------`r`n")
}

$choreworker = 2
foreach ($chore in $chores)
{
    $choremsg[$choreworker - 1] = $choremsg[$choreworker - 1] + $chore.chore + "`r`n"
    $choreworker++
    if ($choreworker -gt $family.count) { $choreworker = 1 }
}

$choremsg = $choremsg + ("`r`nPlus other duties as assigned `r`n")

$choremsg
$choremsgsubject = ("Chores for " + $today)

$smtpconn = new-object system.net.mail.smtpClient
$smtpconn.host = "smtp.gmail.com"
$smtpconn.port = 587
$smtpconn.EnableSsl = $true
$smtpconn.Credentials = new-object system.net.networkcredential($smtpuser,$smtppassword)
foreach ($familymember in $family)
{
    $smtpconn.send('person@gmail.com',$familymember.email,$choremsgsubject,$choremsg)
}

It's a cool bit of powershell that automates dishing out household chores to the family. You need to setup 2 CSV files for this to work.

Chores.csv Chore,Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Weight Feed dog,1,1,1,1,1,1,1,1 Feed cat,1,1,1,1,1,1,1,1 Clean Main Floor Bathroom,0,0,1,0,0,0,1,3 Family.csv Person, Email Dad,dad@gmail.com Mom,mom@gmail.com kid1,kid1@gmail.com kid2,kid2@gmail.com

Once you've got those CSV files we can use the import-csv function to pull them into powershell as objects that we can use!

Give it a try! Fill $family with the content of the CSV
$family = import-csv family.csv

Cool now just type;
$family

You'll see that your CSV is now a powershell object with properties corresponding to the column headers in your CSV.

Now try
$family.person

This'll just give you all the people. Now try
$family.email

This'll output just the emails.

The other thing to note with this script is the foreach command. Basically this is saying for each thing in a group of things do something. This kind of loop is used all the time in powershell and it's worth taking some time to get your head around.

This script is the essence of Everyday Powershell! Scripting with powershell shouldn't be intimidating, it's automation made awesome! The best way to learn is to just get stuck in and start solving problems and I can't think of much better problems to solve than eliminating arguments about who does what around the house!

So big thanks to Reddit user MessageforyouSir for this little gem. It's a been great excuse to play with and learn about import-csv! Oh and remember if you want to schedule a script check out Part 1 of this series.

Security Note - The security aware among you will note that the script requires that you hard-code a password in plain text. This is generally not considered good practice and wouldn't be necessary if you run you own SMTP server that allows relaying. There's probably a post or two just in managing and storing and using credentials in this way. You'll have to stay tuned for those.







Wednesday, October 2, 2013

Everyday Powershell - Part 2 - The BOFH Speaks!

This is the next part in an ongoing series about Powershell. You may have heard about how awesome Powershell is but have struggled to find ways to make it useful in your day to day work. That's what this series is going to address. It'll provide scripts and knowledge to address practical everyday problems!

This script is a bit of fun that we can also use for learning! The everyday problem we're addressing here is the lack of funny in our days. I know you'll also be able to reuse the functions in the script for actual productive work but that shouldn't get in the way of the funny!

First step Fire up the Powershell ISE and paste this in, turn up your speakers, run the script and enjoy the funnies.
#requires -version 2
function Say-Text
{
    param ([Parameter(Mandatory=$true, ValueFromPipeline=$true)] [string] $Text)
    [Reflection.Assembly]::LoadWithPartialName('System.Speech') | Out-Null
    $object = New-Object System.Speech.Synthesis.SpeechSynthesizer
    $object.Speak($Text)
}

function download-file
{
    param ([string]$path, [string]$local)
    $client = new-object system.net.WebClient
    $client.Headers.Add("user-agent", "PowerShell")
    $client.downloadfile($path, $local)
}

$path = "http://www.cs.wisc.edu/~ballard/bofh/excuses"
$local = "c:\temp\temp.html"

download-file $path $local

$excuse = Get-Content $local | get-random
say-text "Today's excuse is... $excuse
"

Then save it as a .ps1 file somewhere sensible and look over Part 1 of this series for the low down on how to schedule this script to run on a daily basis!

Imagine it! You can have your Computer read out a BOFH excuse every day! This... THIS, is why I love Powershell.

Read on for a line by line breakdown of what is actually going on in the script!

Part 1
function Say-Text is actually a cool way to demonstrate functions and have a bit of fun with .net objects.

param ([Parameter(Mandatory=$true, ValueFromPipeline=$true)] [string] $Text) Essentially this is just setting up the parameters that can passed to the function. In this case we're just pulling in a string called $text it's mandatory and can be passed from the pipeline.

[Reflection.Assembly]::LoadWithPartialName('System.Speech') | Out-Null This loads System.speech so we can use it. The pipe to out-null simply prevents dumping this kind of thing to your console...
True   v4.0.30319     C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Speech\v4.0_4.0.0.0__31bf3856ad364e35\System.Speech.dll    

$object = New-Object System.Speech.Synthesis.SpeechSynthesizer This creates a new .net object called $object.
NOTE - Something cool you can try once you've got an object like this is piping to get-member like this;
[Reflection.Assembly]::LoadWithPartialName('System.Speech')$object = New-Object System.Speech.Synthesis.SpeechSynthesizer$object | get-member 
You'll get this useful list of all the methods and properties of the object.
$object.Speak($Text) Next up we simply called the object with the speak method and hand $text as the argument! There you have a talking PC!

Part 2
function download-file Next up is another function This one uses .net to pull down a file from a web server.

param ([string]$path, [string]$local) Same as parameters in the previous function but this time there are 2! You separate them with commas. We're pulling in $path and $local take note of these we'll need them later!

$client = new-object system.net.WebClient Setting up a .net object same as in the previous function but setting up a different kind of object this one is a webclient.

$client.Headers.Add("user-agent", "PowerShell") We've got to do a bit of work to this object before we can use it. Web servers get all funny if you don't give them a user-agent string.

$client.downloadfile($path, $local) This does the work and downloads the thing in $path and saves is in $local.

Part 3
So with the functions setup we move into the main bit of the script 

$path = "http://www.cs.wisc.edu/~ballard/bofh/excuses"
$local = "c:\temp\temp.html"

Recognize those variables? Yup we'll be using them right now!

download-file $path $local So we're calling the function setup earlier with the two variables we just created and set. 

$excuse = Get-Content $local | get-random This sets up a variable $excuse and pipes the content of the file we just downloaded to get-random... This will all become clear (if it's not already)

say-text "Today's excuse is... $excuse" Now we call the function we setup at the start and hands it a bit of text. See what it's doing?! Isn't Powershell cool?!

So this is just a quick example of something neat you can do with powershell. One thing to keep in mind is you can copy and paste those functions and use them in other scripts.

Let me know if you have any trouble with this script by leaving a comment below. Also there's a glaring inefficiency in this script so add a comment pointing out what it is if you can, and for even more kudos suggest a more efficient approach!

Lastly full credit for the say-text function should go to http://mckibbins.info/2013/01/21/powershell-text-to-speech/.